Merge pull request #15858 from yashodha/translation
[civicrm-core.git] / tests / phpunit / api / v3 / ContactTest.php
CommitLineData
6a488035
TO
1<?php
2/**
381fa321 3 * @file
4 * File for the TestContact class.
6a488035
TO
5 *
6 * (PHP 5)
7 *
6c6e6187
TO
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
6a488035 11 * GNU Affero General Public License version 3
6c6e6187
TO
12 * @version $Id: ContactTest.php 31254 2010-12-15 10:09:29Z eileen $
13 * @package CiviCRM
6a488035
TO
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
6a488035
TO
32/**
33 * Test APIv3 civicrm_contact* functions
34 *
6c6e6187
TO
35 * @package CiviCRM_APIv3
36 * @subpackage API_Contact
acb109b7 37 * @group headless
6a488035 38 */
6a488035 39class api_v3_ContactTest extends CiviUnitTestCase {
46312f7d 40
119664d6 41 use CRMTraits_Custom_CustomDataTrait;
42
6a488035 43 public $DBResetRequired = FALSE;
46312f7d 44
6a488035 45 protected $_apiversion;
46312f7d 46
6a488035 47 protected $_entity;
46312f7d 48
6a488035 49 protected $_params;
b7c9bc4c 50
f6722559 51 protected $_contactID;
46312f7d 52
6c6e6187 53 protected $_financialTypeId = 1;
6a488035 54
119664d6 55
56 /**
57 * Entity to be extended.
58 *
59 * @var string
60 */
61 protected $entity = 'Contact';
62
6a488035 63 /**
381fa321 64 * Test setup for every test.
6a488035 65 *
d177a2a6
EM
66 * Connect to the database, truncate the tables that will be used
67 * and redirect stdin to a temporary file
6a488035
TO
68 */
69 public function setUp() {
381fa321 70 // Connect to the database.
6a488035 71 parent::setUp();
f6722559 72 $this->_entity = 'contact';
46312f7d 73 $this->_params = [
6a488035
TO
74 'first_name' => 'abc1',
75 'contact_type' => 'Individual',
76 'last_name' => 'xyz1',
46312f7d 77 ];
6a488035
TO
78 }
79
701a69da 80 /**
81 * Restore the DB for the next test.
82 *
83 * @throws \Exception
84 */
00be9182 85 public function tearDown() {
2d932085 86 $this->_apiversion = 3;
46312f7d 87 $this->callAPISuccess('Setting', 'create', ['includeOrderByClause' => TRUE]);
6a488035 88 // truncate a few tables
46312f7d 89 $tablesToTruncate = [
6a488035
TO
90 'civicrm_email',
91 'civicrm_contribution',
92 'civicrm_line_item',
93 'civicrm_website',
e635f9d4
TO
94 'civicrm_relationship',
95 'civicrm_uf_match',
405f289b 96 'civicrm_phone',
e9e27a80 97 'civicrm_address',
1ca22999 98 'civicrm_acl_contact_cache',
5ea06a7b 99 'civicrm_activity_contact',
100 'civicrm_activity',
0626851e 101 'civicrm_group',
102 'civicrm_group_contact',
103 'civicrm_saved_search',
104 'civicrm_group_contact_cache',
e13fa54b 105 'civicrm_prevnext_cache',
46312f7d 106 ];
6a488035 107
f6722559 108 $this->quickCleanup($tablesToTruncate, TRUE);
1ca22999 109 parent::tearDown();
6a488035
TO
110 }
111
112 /**
381fa321 113 * Test civicrm_contact_create.
6a488035 114 *
381fa321 115 * Verify that attempt to create individual contact with only
116 * first and last names succeeds
2d932085
CW
117 *
118 * @param int $version
46312f7d 119 *
2d932085 120 * @dataProvider versionThreeAndFour
6a488035 121 */
2d932085
CW
122 public function testAddCreateIndividual($version) {
123 $this->_apiversion = $version;
6a488035 124 $oldCount = CRM_Core_DAO::singleValueQuery('select count(*) from civicrm_contact');
46312f7d 125 $params = [
6a488035
TO
126 'first_name' => 'abc1',
127 'contact_type' => 'Individual',
128 'last_name' => 'xyz1',
46312f7d 129 ];
6a488035 130
f6722559 131 $contact = $this->callAPISuccess('contact', 'create', $params);
fe482240
EM
132 $this->assertTrue(is_numeric($contact['id']));
133 $this->assertTrue($contact['id'] > 0);
6a488035 134 $newCount = CRM_Core_DAO::singleValueQuery('select count(*) from civicrm_contact');
6c6e6187 135 $this->assertEquals($oldCount + 1, $newCount);
6a488035 136
6a488035
TO
137 $this->assertDBState('CRM_Contact_DAO_Contact',
138 $contact['id'],
139 $params
140 );
141 }
142
ec52a65a 143 /**
144 * Test that it is possible to prevent cache clearing via option.
145 *
146 * Cache clearing is bypassed if 'options' => array('do_not_reset_cache' => 1 is used.
147 */
148 public function testCreateIndividualNoCacheClear() {
149
150 $contact = $this->callAPISuccess('contact', 'create', $this->_params);
151 $groupID = $this->groupCreate();
152
153 $this->putGroupContactCacheInClearableState($groupID, $contact);
154
46312f7d 155 $this->callAPISuccess('contact', 'create', ['id' => $contact['id']]);
ec52a65a 156 $this->assertEquals(0, CRM_Core_DAO::singleValueQuery("SELECT count(*) FROM civicrm_group_contact_cache"));
157
158 // Rinse & repeat, but with the option.
159 $this->putGroupContactCacheInClearableState($groupID, $contact);
0626851e 160 CRM_Core_Config::setPermitCacheFlushMode(FALSE);
46312f7d 161 $this->callAPISuccess('contact', 'create', ['id' => $contact['id']]);
ec52a65a 162 $this->assertEquals(1, CRM_Core_DAO::singleValueQuery("SELECT count(*) FROM civicrm_group_contact_cache"));
0626851e 163 CRM_Core_Config::setPermitCacheFlushMode(TRUE);
ec52a65a 164 }
165
3a15378c 166 /**
167 * Test for international string acceptance (CRM-10210).
828cd10c 168 * Requires the databsase to be in utf8.
3a15378c 169 *
170 * @dataProvider getInternationalStrings
171 *
172 * @param string $string
173 * String to be tested.
2fc64082 174 *
828cd10c 175 * Bool to see if we should check charset.
3a15378c 176 *
177 * @throws \Exception
178 */
2fc64082 179 public function testInternationalStrings($string) {
3a15378c 180 $this->callAPISuccess('Contact', 'create', array_merge(
181 $this->_params,
46312f7d 182 ['first_name' => $string]
3a15378c 183 ));
2fc64082 184
46312f7d 185 $result = $this->callAPISuccessGetSingle('Contact', ['first_name' => $string]);
3a15378c 186 $this->assertEquals($string, $result['first_name']);
187
46312f7d 188 $organizationParams = [
3a15378c 189 'organization_name' => $string,
190 'contact_type' => 'Organization',
46312f7d 191 ];
3a15378c 192
193 $this->callAPISuccess('Contact', 'create', $organizationParams);
194 $result = $this->callAPISuccessGetSingle('Contact', $organizationParams);
195 $this->assertEquals($string, $result['organization_name']);
196 }
197
198 /**
199 * Get international string data for testing against api calls.
200 */
201 public function getInternationalStrings() {
46312f7d 202 $invocations = [];
203 $invocations[] = ['Scarabée'];
204 $invocations[] = ['Iñtërnâtiônàlizætiøn'];
205 $invocations[] = ['これは日本語のテキストです。読めますか'];
206 $invocations[] = ['देखें हिन्दी कैसी नजर आती है। अरे वाह ये तो नजर आती है।'];
3a15378c 207 return $invocations;
208 }
209
b99f9616 210 /**
211 * Test civicrm_contact_create.
212 *
213 * Verify that preferred language can be set.
46312f7d 214 *
2d932085 215 * @param int $version
46312f7d 216 *
2d932085 217 * @dataProvider versionThreeAndFour
b99f9616 218 */
2d932085
CW
219 public function testAddCreateIndividualWithPreferredLanguage($version) {
220 $this->_apiversion = $version;
46312f7d 221 $params = [
b99f9616 222 'first_name' => 'abc1',
223 'contact_type' => 'Individual',
224 'last_name' => 'xyz1',
225 'preferred_language' => 'es_ES',
46312f7d 226 ];
b99f9616 227
228 $contact = $this->callAPISuccess('contact', 'create', $params);
229 $this->getAndCheck($params, $contact['id'], 'Contact');
230 }
231
6a488035 232 /**
381fa321 233 * Test civicrm_contact_create with sub-types.
6a488035 234 *
381fa321 235 * Verify that sub-types are created successfully and not deleted by subsequent updates.
2d932085 236 *
646b5400 237 * @param int $version
46312f7d 238 *
646b5400 239 * @dataProvider versionThreeAndFour
6a488035 240 */
646b5400
CW
241 public function testIndividualSubType($version) {
242 $this->_apiversion = $version;
46312f7d 243 $params = [
6a488035
TO
244 'first_name' => 'test abc',
245 'contact_type' => 'Individual',
246 'last_name' => 'test xyz',
46312f7d 247 'contact_sub_type' => ['Student', 'Staff'],
248 ];
f6722559 249 $contact = $this->callAPISuccess('contact', 'create', $params);
6a488035
TO
250 $cid = $contact['id'];
251
46312f7d 252 $params = [
6a488035
TO
253 'id' => $cid,
254 'middle_name' => 'foo',
46312f7d 255 ];
f6722559 256 $this->callAPISuccess('contact', 'create', $params);
6a488035 257
c15b5652 258 $contact = $this->callAPISuccess('contact', 'get', ['id' => $cid]);
6a488035 259
46312f7d 260 $this->assertEquals(['Student', 'Staff'], $contact['values'][$cid]['contact_sub_type']);
c15b5652
CW
261
262 $this->callAPISuccess('Contact', 'create', [
263 'id' => $cid,
264 'contact_sub_type' => [],
265 ]);
266
267 $contact = $this->callAPISuccess('contact', 'get', ['id' => $cid]);
268 $this->assertTrue(empty($contact['values'][$cid]['contact_sub_type']));
6a488035
TO
269 }
270
35fbf8a2
MM
271 /**
272 * Verify that we can retreive contacts of different sub types
46312f7d 273 *
2d932085 274 * @param int $version
46312f7d 275 *
2d932085 276 * @dataProvider versionThreeAndFour
35fbf8a2 277 */
2d932085
CW
278 public function testGetMultipleContactSubTypes($version) {
279 $this->_apiversion = $version;
35fbf8a2
MM
280
281 // This test presumes that there are no parents or students in the dataset
282
283 // create a student
46312f7d 284 $student = $this->callAPISuccess('contact', 'create', [
35fbf8a2
MM
285 'email' => 'student@example.com',
286 'contact_type' => 'Individual',
287 'contact_sub_type' => 'Student',
46312f7d 288 ]);
35fbf8a2
MM
289
290 // create a parent
46312f7d 291 $parent = $this->callAPISuccess('contact', 'create', [
35fbf8a2
MM
292 'email' => 'parent@example.com',
293 'contact_type' => 'Individual',
294 'contact_sub_type' => 'Parent',
46312f7d 295 ]);
35fbf8a2
MM
296
297 // create a parent
46312f7d 298 $this->callAPISuccess('contact', 'create', [
35fbf8a2
MM
299 'email' => 'parent@example.com',
300 'contact_type' => 'Individual',
46312f7d 301 ]);
35fbf8a2
MM
302
303 // get all students and parents
46312f7d 304 $getParams = ['contact_sub_type' => ['IN' => ['Parent', 'Student']]];
35fbf8a2
MM
305 $result = civicrm_api3('contact', 'get', $getParams);
306
307 // check that we retrieved the student and the parent
308 $this->assertArrayHasKey($student['id'], $result['values']);
309 $this->assertArrayHasKey($parent['id'], $result['values']);
310 $this->assertEquals(2, $result['count']);
311
312 }
313
6a488035 314 /**
381fa321 315 * Verify that attempt to create contact with empty params fails.
6a488035 316 */
00be9182 317 public function testCreateEmptyContact() {
46312f7d 318 $this->callAPIFailure('contact', 'create', []);
6a488035
TO
319 }
320
321 /**
381fa321 322 * Verify that attempt to create contact with bad contact type fails.
6a488035 323 */
00be9182 324 public function testCreateBadTypeContact() {
46312f7d 325 $params = [
6a488035
TO
326 'email' => 'man1@yahoo.com',
327 'contact_type' => 'Does not Exist',
46312f7d 328 ];
6c6e6187 329 $this->callAPIFailure('contact', 'create', $params, "'Does not Exist' is not a valid option for field contact_type");
6a488035
TO
330 }
331
332 /**
381fa321 333 * Verify that attempt to create individual contact without required fields fails.
6a488035 334 */
00be9182 335 public function testCreateBadRequiredFieldsIndividual() {
46312f7d 336 $params = [
6a488035
TO
337 'middle_name' => 'This field is not required',
338 'contact_type' => 'Individual',
46312f7d 339 ];
4b58ed3b 340 $this->callAPIFailure('contact', 'create', $params);
6a488035
TO
341 }
342
343 /**
381fa321 344 * Verify that attempt to create household contact without required fields fails.
6a488035 345 */
00be9182 346 public function testCreateBadRequiredFieldsHousehold() {
46312f7d 347 $params = [
6a488035
TO
348 'middle_name' => 'This field is not required',
349 'contact_type' => 'Household',
46312f7d 350 ];
4b58ed3b 351 $this->callAPIFailure('contact', 'create', $params);
6a488035
TO
352 }
353
354 /**
381fa321 355 * Test required field check.
356 *
357 * Verify that attempt to create organization contact without required fields fails.
6a488035 358 */
00be9182 359 public function testCreateBadRequiredFieldsOrganization() {
46312f7d 360 $params = [
6a488035
TO
361 'middle_name' => 'This field is not required',
362 'contact_type' => 'Organization',
46312f7d 363 ];
6a488035 364
4b58ed3b 365 $this->callAPIFailure('contact', 'create', $params);
6a488035
TO
366 }
367
368 /**
381fa321 369 * Verify that attempt to create individual contact with only an email succeeds.
b69793be 370 *
371 * @throws \CRM_Core_Exception
6a488035 372 */
00be9182 373 public function testCreateEmailIndividual() {
57f8e7f0 374 $primaryEmail = 'man3@yahoo.com';
375 $notPrimaryEmail = 'man4@yahoo.com';
46312f7d 376 $params = [
57f8e7f0 377 'email' => $primaryEmail,
6a488035
TO
378 'contact_type' => 'Individual',
379 'location_type_id' => 1,
46312f7d 380 ];
6a488035 381
57f8e7f0 382 $contact1 = $this->callAPISuccess('contact', 'create', $params);
383
384 $this->assertEquals(3, $contact1['id']);
46312f7d 385 $email1 = $this->callAPISuccess('email', 'get', ['contact_id' => $contact1['id']]);
57f8e7f0 386 $this->assertEquals(1, $email1['count']);
387 $this->assertEquals($primaryEmail, $email1['values'][$email1['id']]['email']);
388
46312f7d 389 $email2 = $this->callAPISuccess('email', 'create', ['contact_id' => $contact1['id'], 'is_primary' => 0, 'email' => $notPrimaryEmail]);
57f8e7f0 390
391 // Case 1: Check with criteria primary 'email' => array('IS NOT NULL' => 1)
46312f7d 392 $result = $this->callAPISuccess('contact', 'get', ['email' => ['IS NOT NULL' => 1]]);
57f8e7f0 393 $primaryEmailContactIds = array_keys($result['values']);
394 $this->assertEquals($primaryEmail, $email1['values'][$email1['id']]['email']);
395
396 // Case 2: Check with criteria primary 'email' => array('<>' => '')
46312f7d 397 $result = $this->callAPISuccess('contact', 'get', ['email' => ['<>' => '']]);
57f8e7f0 398 $primaryEmailContactIds = array_keys($result['values']);
399 $this->assertEquals($primaryEmail, $email1['values'][$email1['id']]['email']);
f6722559 400
57f8e7f0 401 // Case 3: Check with email_id='primary email id'
b69793be 402 $result = $this->callAPISuccessGetSingle('contact', ['email_id' => $email1['id']]);
57f8e7f0 403 $this->assertEquals($contact1['id'], $result['id']);
6a488035 404
b69793be 405 // Check no wildcard is appended
406 $this->callAPISuccessGetCount('Contact', ['email' => 'man3@yahoo.co'], 0);
407
57f8e7f0 408 $this->callAPISuccess('contact', 'delete', $contact1);
6a488035
TO
409 }
410
411 /**
381fa321 412 * Test creating individual by name.
413 *
414 * Verify create individual contact with only first and last names succeeds.
46312f7d 415 *
2d932085 416 * @param int $version
46312f7d 417 *
2d932085 418 * @dataProvider versionThreeAndFour
6a488035 419 */
2d932085
CW
420 public function testCreateNameIndividual($version) {
421 $this->_apiversion = $version;
46312f7d 422 $params = [
6a488035
TO
423 'first_name' => 'abc1',
424 'contact_type' => 'Individual',
425 'last_name' => 'xyz1',
46312f7d 426 ];
6a488035 427
c8747697 428 $this->callAPISuccess('contact', 'create', $params);
6a488035
TO
429 }
430
c10e7177 431 /**
432 * Test creating individual by display_name.
433 *
434 * Display name & sort name should be set.
46312f7d 435 *
2d932085 436 * @param int $version
46312f7d 437 *
2d932085 438 * @dataProvider versionThreeAndFour
c10e7177 439 */
2d932085
CW
440 public function testCreateDisplayNameIndividual($version) {
441 $this->_apiversion = $version;
46312f7d 442 $params = [
c10e7177 443 'display_name' => 'abc1',
444 'contact_type' => 'Individual',
46312f7d 445 ];
c10e7177 446
447 $contact = $this->callAPISuccess('contact', 'create', $params);
448 $params['sort_name'] = 'abc1';
449 $this->getAndCheck($params, $contact['id'], 'contact');
450 }
451
9436d5d5 452 /**
453 * Test that name searches are case insensitive.
46312f7d 454 *
2d932085 455 * @param int $version
46312f7d 456 *
2d932085 457 * @dataProvider versionThreeAndFour
9436d5d5 458 */
2d932085
CW
459 public function testGetNameVariantsCaseInsensitive($version) {
460 $this->_apiversion = $version;
9436d5d5 461 $this->callAPISuccess('contact', 'create', [
462 'display_name' => 'Abc1',
463 'contact_type' => 'Individual',
464 ]);
465 $this->callAPISuccessGetSingle('Contact', ['display_name' => 'aBc1']);
466 $this->callAPISuccessGetSingle('Contact', ['sort_name' => 'aBc1']);
467 Civi::settings()->set('includeNickNameInName', TRUE);
2d932085 468 $result = $this->callAPISuccessGetSingle('Contact', ['display_name' => 'aBc1']);
9436d5d5 469 $this->callAPISuccessGetSingle('Contact', ['sort_name' => 'aBc1']);
470 Civi::settings()->set('includeNickNameInName', FALSE);
471 }
472
6a488035 473 /**
381fa321 474 * Test old keys still work.
475 *
476 * Verify that attempt to create individual contact with
d177a2a6 477 * first and last names and old key values works
6a488035 478 */
00be9182 479 public function testCreateNameIndividualOldKeys() {
46312f7d 480 $params = [
6a488035
TO
481 'individual_prefix' => 'Dr.',
482 'first_name' => 'abc1',
483 'contact_type' => 'Individual',
484 'last_name' => 'xyz1',
485 'individual_suffix' => 'Jr.',
46312f7d 486 ];
6a488035 487
f6722559 488 $contact = $this->callAPISuccess('contact', 'create', $params);
46312f7d 489 $result = $this->callAPISuccess('contact', 'getsingle', ['id' => $contact['id']]);
fd651abc 490
a1255c80
CW
491 $this->assertArrayKeyExists('prefix_id', $result);
492 $this->assertArrayKeyExists('suffix_id', $result);
493 $this->assertArrayKeyExists('gender_id', $result);
494 $this->assertEquals(4, $result['prefix_id']);
495 $this->assertEquals(1, $result['suffix_id']);
6a488035
TO
496 }
497
498 /**
381fa321 499 * Test preferred keys work.
500 *
501 * Verify that attempt to create individual contact with
d177a2a6 502 * first and last names and old key values works
6a488035 503 */
381fa321 504 public function testCreateNameIndividualRecommendedKeys2() {
46312f7d 505 $params = [
6a488035
TO
506 'prefix_id' => 'Dr.',
507 'first_name' => 'abc1',
508 'contact_type' => 'Individual',
509 'last_name' => 'xyz1',
510 'suffix_id' => 'Jr.',
511 'gender_id' => 'Male',
46312f7d 512 ];
6a488035 513
f6722559 514 $contact = $this->callAPISuccess('contact', 'create', $params);
46312f7d 515 $result = $this->callAPISuccess('contact', 'getsingle', ['id' => $contact['id']]);
fd651abc 516
a1255c80
CW
517 $this->assertArrayKeyExists('prefix_id', $result);
518 $this->assertArrayKeyExists('suffix_id', $result);
519 $this->assertArrayKeyExists('gender_id', $result);
520 $this->assertEquals(4, $result['prefix_id']);
521 $this->assertEquals(1, $result['suffix_id']);
6a488035
TO
522 }
523
524 /**
381fa321 525 * Test household name is sufficient for create.
526 *
527 * Verify that attempt to create household contact with only
d177a2a6 528 * household name succeeds
46312f7d 529 *
2d932085 530 * @param int $version
46312f7d 531 *
2d932085 532 * @dataProvider versionThreeAndFour
6a488035 533 */
2d932085
CW
534 public function testCreateNameHousehold($version) {
535 $this->_apiversion = $version;
46312f7d 536 $params = [
6a488035
TO
537 'household_name' => 'The abc Household',
538 'contact_type' => 'Household',
46312f7d 539 ];
c8747697 540 $this->callAPISuccess('contact', 'create', $params);
6a488035
TO
541 }
542
543 /**
381fa321 544 * Test organization name is sufficient for create.
545 *
546 * Verify that attempt to create organization contact with only
d177a2a6 547 * organization name succeeds.
46312f7d 548 *
2d932085 549 * @param int $version
46312f7d 550 *
2d932085 551 * @dataProvider versionThreeAndFour
6a488035 552 */
2d932085
CW
553 public function testCreateNameOrganization($version) {
554 $this->_apiversion = $version;
46312f7d 555 $params = [
6a488035
TO
556 'organization_name' => 'The abc Organization',
557 'contact_type' => 'Organization',
46312f7d 558 ];
c8747697 559 $this->callAPISuccess('contact', 'create', $params);
6a488035 560 }
5896d037 561
6a488035 562 /**
381fa321 563 * Verify that attempt to create organization contact without organization name fails.
6a488035 564 */
00be9182 565 public function testCreateNoNameOrganization() {
46312f7d 566 $params = [
6a488035
TO
567 'first_name' => 'The abc Organization',
568 'contact_type' => 'Organization',
46312f7d 569 ];
4b58ed3b 570 $this->callAPIFailure('contact', 'create', $params);
6a488035 571 }
5896d037 572
ea33395c
TO
573 /**
574 * Check that permissions on API key are restricted (CRM-18112).
2d932085
CW
575 *
576 * @param int $version
46312f7d 577 *
2d932085 578 * @dataProvider versionThreeAndFour
ea33395c 579 */
2d932085
CW
580 public function testCreateApiKey($version) {
581 $this->_apiversion = $version;
ea33395c 582 $config = CRM_Core_Config::singleton();
46312f7d 583 $contactId = $this->individualCreate([
ea33395c
TO
584 'first_name' => 'A',
585 'last_name' => 'B',
46312f7d 586 ]);
ea33395c
TO
587
588 // Allow edit -- because permissions aren't being checked
46312f7d 589 $config->userPermissionClass->permissions = [];
590 $result = $this->callAPISuccess('Contact', 'create', [
ea33395c
TO
591 'id' => $contactId,
592 'api_key' => 'original',
46312f7d 593 ]);
ea33395c
TO
594 $this->assertEquals('original', $result['values'][$contactId]['api_key']);
595
596 // Allow edit -- because we have adequate permission
46312f7d 597 $config->userPermissionClass->permissions = ['access CiviCRM', 'edit all contacts', 'edit api keys'];
598 $result = $this->callAPISuccess('Contact', 'create', [
ea33395c
TO
599 'check_permissions' => 1,
600 'id' => $contactId,
601 'api_key' => 'abcd1234',
46312f7d 602 ]);
ea33395c
TO
603 $this->assertEquals('abcd1234', $result['values'][$contactId]['api_key']);
604
605 // Disallow edit -- because we don't have permission
46312f7d 606 $config->userPermissionClass->permissions = ['access CiviCRM', 'edit all contacts'];
607 $result = $this->callAPIFailure('Contact', 'create', [
ea33395c
TO
608 'check_permissions' => 1,
609 'id' => $contactId,
610 'api_key' => 'defg4321',
46312f7d 611 ]);
ea33395c
TO
612 $this->assertRegExp(';Permission denied to modify api key;', $result['error_message']);
613
614 // Return everything -- because permissions are not being checked
46312f7d 615 $config->userPermissionClass->permissions = [];
616 $result = $this->callAPISuccess('Contact', 'create', [
ea33395c
TO
617 'id' => $contactId,
618 'first_name' => 'A2',
46312f7d 619 ]);
ea33395c
TO
620 $this->assertEquals('A2', $result['values'][$contactId]['first_name']);
621 $this->assertEquals('B', $result['values'][$contactId]['last_name']);
622 $this->assertEquals('abcd1234', $result['values'][$contactId]['api_key']);
623
624 // Return everything -- because we have adequate permission
46312f7d 625 $config->userPermissionClass->permissions = ['access CiviCRM', 'edit all contacts', 'edit api keys'];
626 $result = $this->callAPISuccess('Contact', 'create', [
ea33395c
TO
627 'check_permissions' => 1,
628 'id' => $contactId,
629 'first_name' => 'A3',
46312f7d 630 ]);
ea33395c
TO
631 $this->assertEquals('A3', $result['values'][$contactId]['first_name']);
632 $this->assertEquals('B', $result['values'][$contactId]['last_name']);
633 $this->assertEquals('abcd1234', $result['values'][$contactId]['api_key']);
634
635 // Restricted return -- because we don't have permission
46312f7d 636 $config->userPermissionClass->permissions = ['access CiviCRM', 'edit all contacts'];
637 $result = $this->callAPISuccess('Contact', 'create', [
ea33395c
TO
638 'check_permissions' => 1,
639 'id' => $contactId,
640 'first_name' => 'A4',
46312f7d 641 ]);
ea33395c
TO
642 $this->assertEquals('A4', $result['values'][$contactId]['first_name']);
643 $this->assertEquals('B', $result['values'][$contactId]['last_name']);
644 $this->assertTrue(empty($result['values'][$contactId]['api_key']));
645 }
646
6a488035 647 /**
381fa321 648 * Check with complete array + custom field.
649 *
6a488035
TO
650 * Note that the test is written on purpose without any
651 * variables specific to participant so it can be replicated into other entities
652 * and / or moved to the automated test suite
46312f7d 653 *
2d932085 654 * @param int $version
46312f7d 655 *
2d932085 656 * @dataProvider versionThreeAndFour
6a488035 657 */
2d932085
CW
658 public function testCreateWithCustom($version) {
659 $this->_apiversion = $version;
6a488035
TO
660 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
661
662 $params = $this->_params;
663 $params['custom_' . $ids['custom_field_id']] = "custom string";
5c49fee0 664 $description = "This demonstrates setting a custom field through the API.";
fb32de45 665 $result = $this->callAPIAndDocument($this->_entity, 'create', $params, __FUNCTION__, __FILE__, $description);
6a488035 666
46312f7d 667 $check = $this->callAPISuccess($this->_entity, 'get', [
92915c55
TO
668 'return.custom_' . $ids['custom_field_id'] => 1,
669 'id' => $result['id'],
46312f7d 670 ]);
4b58ed3b 671 $this->assertEquals("custom string", $check['values'][$check['id']]['custom_' . $ids['custom_field_id']]);
6a488035
TO
672
673 $this->customFieldDelete($ids['custom_field_id']);
674 $this->customGroupDelete($ids['custom_group_id']);
675 }
676
fe6daa04 677 /**
381fa321 678 * CRM-12773 - expectation is that civicrm quietly ignores fields without values.
fe6daa04 679 */
00be9182 680 public function testCreateWithNULLCustomCRM12773() {
fe6daa04 681 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
682 $params = $this->_params;
683 $params['custom_' . $ids['custom_field_id']] = NULL;
4b58ed3b 684 $this->callAPISuccess('contact', 'create', $params);
fe6daa04 685 $this->customFieldDelete($ids['custom_field_id']);
686 $this->customGroupDelete($ids['custom_group_id']);
687 }
688
9747df8a 689 /**
690 * CRM-14232 test preferred language set to site default if not passed.
46312f7d 691 *
2d932085 692 * @param int $version
46312f7d 693 *
2d932085 694 * @dataProvider versionThreeAndFour
9747df8a 695 */
2d932085
CW
696 public function testCreatePreferredLanguageUnset($version) {
697 $this->_apiversion = $version;
46312f7d 698 $this->callAPISuccess('Contact', 'create', [
9747df8a 699 'first_name' => 'Snoop',
700 'last_name' => 'Dog',
39b959db 701 'contact_type' => 'Individual',
46312f7d 702 ]);
703 $result = $this->callAPISuccessGetSingle('Contact', ['last_name' => 'Dog']);
9747df8a 704 $this->assertEquals('en_US', $result['preferred_language']);
705 }
706
707 /**
708 * CRM-14232 test preferred language returns setting if not passed.
46312f7d 709 *
2d932085 710 * @param int $version
46312f7d 711 *
2d932085 712 * @dataProvider versionThreeAndFour
9747df8a 713 */
2d932085
CW
714 public function testCreatePreferredLanguageSet($version) {
715 $this->_apiversion = $version;
46312f7d 716 $this->callAPISuccess('Setting', 'create', ['contact_default_language' => 'fr_FR']);
717 $this->callAPISuccess('Contact', 'create', [
9747df8a 718 'first_name' => 'Snoop',
719 'last_name' => 'Dog',
720 'contact_type' => 'Individual',
46312f7d 721 ]);
722 $result = $this->callAPISuccessGetSingle('Contact', ['last_name' => 'Dog']);
9747df8a 723 $this->assertEquals('fr_FR', $result['preferred_language']);
724 }
725
726 /**
727 * CRM-14232 test preferred language returns setting if not passed where setting is NULL.
2d932085 728 * TODO: Api4
9747df8a 729 */
730 public function testCreatePreferredLanguageNull() {
46312f7d 731 $this->callAPISuccess('Setting', 'create', ['contact_default_language' => 'null']);
732 $this->callAPISuccess('Contact', 'create', [
39b959db
SL
733 'first_name' => 'Snoop',
734 'last_name' => 'Dog',
735 'contact_type' => 'Individual',
46312f7d 736 ]);
737 $result = $this->callAPISuccessGetSingle('Contact', ['last_name' => 'Dog']);
9747df8a 738 $this->assertEquals(NULL, $result['preferred_language']);
739 }
740
741 /**
742 * CRM-14232 test preferred language returns setting if not passed where setting is NULL.
46312f7d 743 *
2d932085 744 * @param int $version
46312f7d 745 *
2d932085 746 * @dataProvider versionThreeAndFour
9747df8a 747 */
2d932085
CW
748 public function testCreatePreferredLanguagePassed($version) {
749 $this->_apiversion = $version;
46312f7d 750 $this->callAPISuccess('Setting', 'create', ['contact_default_language' => 'null']);
751 $this->callAPISuccess('Contact', 'create', [
9747df8a 752 'first_name' => 'Snoop',
753 'last_name' => 'Dog',
754 'contact_type' => 'Individual',
755 'preferred_language' => 'en_AU',
46312f7d 756 ]);
757 $result = $this->callAPISuccessGetSingle('Contact', ['last_name' => 'Dog']);
9747df8a 758 $this->assertEquals('en_AU', $result['preferred_language']);
759 }
760
2930d67a 761 /**
762 * CRM-15792 - create/update datetime field for contact.
763 */
764 public function testCreateContactCustomFldDateTime() {
46312f7d 765 $customGroup = $this->customGroupCreate(['extends' => 'Individual', 'title' => 'datetime_test_group']);
2930d67a 766 $dateTime = CRM_Utils_Date::currentDBDate();
767 //check date custom field is saved along with time when time_format is set
46312f7d 768 $params = [
2930d67a 769 'first_name' => 'abc3',
770 'last_name' => 'xyz3',
771 'contact_type' => 'Individual',
772 'email' => 'man3@yahoo.com',
46312f7d 773 'api.CustomField.create' => [
2930d67a 774 'custom_group_id' => $customGroup['id'],
775 'name' => 'test_datetime',
776 'label' => 'Demo Date',
777 'html_type' => 'Select Date',
778 'data_type' => 'Date',
779 'time_format' => 2,
780 'weight' => 4,
781 'is_required' => 1,
782 'is_searchable' => 0,
783 'is_active' => 1,
46312f7d 784 ],
785 ];
2930d67a 786
3c27d467 787 $result = $this->callAPISuccess('Contact', 'create', $params);
2930d67a 788 $customFldId = $result['values'][$result['id']]['api.CustomField.create']['id'];
ba4a1892 789 $this->assertNotNull($result['id']);
a15773db 790 $this->assertNotNull($customFldId);
2930d67a 791
46312f7d 792 $params = [
2930d67a 793 'id' => $result['id'],
794 "custom_{$customFldId}" => $dateTime,
795 'api.CustomValue.get' => 1,
46312f7d 796 ];
2930d67a 797
3c27d467 798 $result = $this->callAPISuccess('Contact', 'create', $params);
ba4a1892 799 $this->assertNotNull($result['id']);
2930d67a 800 $customFldDate = date("YmdHis", strtotime($result['values'][$result['id']]['api.CustomValue.get']['values'][0]['latest']));
a15773db 801 $this->assertNotNull($customFldDate);
2930d67a 802 $this->assertEquals($dateTime, $customFldDate);
803 $customValueId = $result['values'][$result['id']]['api.CustomValue.get']['values'][0]['id'];
804 $dateTime = date('Ymd');
805 //date custom field should not contain time part when time_format is null
46312f7d 806 $params = [
2930d67a 807 'id' => $result['id'],
46312f7d 808 'api.CustomField.create' => [
41755648 809 'id' => $customFldId,
2930d67a 810 'html_type' => 'Select Date',
811 'data_type' => 'Date',
812 'time_format' => '',
46312f7d 813 ],
814 'api.CustomValue.create' => [
2930d67a 815 'id' => $customValueId,
816 'entity_id' => $result['id'],
817 "custom_{$customFldId}" => $dateTime,
46312f7d 818 ],
2930d67a 819 'api.CustomValue.get' => 1,
46312f7d 820 ];
3c27d467 821 $result = $this->callAPISuccess('Contact', 'create', $params);
ba4a1892 822 $this->assertNotNull($result['id']);
2930d67a 823 $customFldDate = date("Ymd", strtotime($result['values'][$result['id']]['api.CustomValue.get']['values'][0]['latest']));
824 $customFldTime = date("His", strtotime($result['values'][$result['id']]['api.CustomValue.get']['values'][0]['latest']));
a15773db 825 $this->assertNotNull($customFldDate);
2930d67a 826 $this->assertEquals($dateTime, $customFldDate);
827 $this->assertEquals(000000, $customFldTime);
3c27d467 828 $this->callAPISuccess('Contact', 'create', $params);
2930d67a 829 }
830
d424ffde 831 /**
381fa321 832 * Test creating a current employer through API.
6a488035 833 */
5896d037 834 public function testContactCreateCurrentEmployer() {
381fa321 835 // Here we will just do the get for set-up purposes.
46312f7d 836 $count = $this->callAPISuccess('contact', 'getcount', [
6a488035 837 'organization_name' => 'new employer org',
21dfd5f5 838 'contact_type' => 'Organization',
46312f7d 839 ]);
6a488035 840 $this->assertEquals(0, $count);
46312f7d 841 $employerResult = $this->callAPISuccess('contact', 'create', array_merge($this->_params, [
39b959db 842 'current_employer' => 'new employer org',
46312f7d 843 ]));
bb043d6f 844 // do it again as an update to check it doesn't cause an error
46312f7d 845 $employerResult = $this->callAPISuccess('contact', 'create', array_merge($this->_params, [
39b959db
SL
846 'current_employer' => 'new employer org',
847 'id' => $employerResult['id'],
46312f7d 848 ]));
f6722559 849 $expectedCount = 1;
46312f7d 850 $this->callAPISuccess('contact', 'getcount', [
39b959db
SL
851 'organization_name' => 'new employer org',
852 'contact_type' => 'Organization',
46312f7d 853 ], $expectedCount);
6a488035 854
46312f7d 855 $result = $this->callAPISuccess('contact', 'getsingle', [
6a488035 856 'id' => $employerResult['id'],
46312f7d 857 ]);
6a488035
TO
858
859 $this->assertEquals('new employer org', $result['current_employer']);
860
861 }
5896d037 862
d424ffde 863 /**
381fa321 864 * Test creating a current employer through API.
865 *
866 * Check it will re-activate a de-activated employer
d424ffde 867 */
5896d037 868 public function testContactCreateDuplicateCurrentEmployerEnables() {
381fa321 869 // Set up - create employer relationship.
46312f7d 870 $employerResult = $this->callAPISuccess('contact', 'create', array_merge($this->_params, ['current_employer' => 'new employer org']));
871 $relationship = $this->callAPISuccess('relationship', 'get', [
bb043d6f 872 'contact_id_a' => $employerResult['id'],
46312f7d 873 ]);
bb043d6f
E
874
875 //disable & check it is disabled
46312f7d 876 $this->callAPISuccess('relationship', 'create', ['id' => $relationship['id'], 'is_active' => 0]);
877 $this->callAPISuccess('relationship', 'getvalue', [
bb043d6f 878 'id' => $relationship['id'],
21dfd5f5 879 'return' => 'is_active',
46312f7d 880 ], 0);
bb043d6f 881
381fa321 882 // Re-set the current employer - thus enabling the relationship.
46312f7d 883 $this->callAPISuccess('contact', 'create', array_merge($this->_params, [
39b959db
SL
884 'current_employer' => 'new employer org',
885 'id' => $employerResult['id'],
46312f7d 886 ]));
bb043d6f 887 //check is_active is now 1
46312f7d 888 $relationship = $this->callAPISuccess('relationship', 'getsingle', ['return' => 'is_active']);
6c6e6187 889 $this->assertEquals(1, $relationship['is_active']);
bb043d6f
E
890 }
891
8f32b005 892 /**
381fa321 893 * Check deceased contacts are not retrieved.
894 *
895 * Note at time of writing the default is to return default. This should possibly be changed & test added.
46312f7d 896 *
2d932085 897 * @param int $version
46312f7d 898 *
2d932085 899 * @dataProvider versionThreeAndFour
8f32b005 900 */
2d932085
CW
901 public function testGetDeceasedRetrieved($version) {
902 $this->_apiversion = $version;
4b58ed3b 903 $this->callAPISuccess($this->_entity, 'create', $this->_params);
46312f7d 904 $c2 = $this->callAPISuccess($this->_entity, 'create', [
92915c55
TO
905 'first_name' => 'bb',
906 'last_name' => 'ccc',
907 'contact_type' => 'Individual',
908 'is_deceased' => 1,
46312f7d 909 ]);
910 $result = $this->callAPISuccess($this->_entity, 'get', ['is_deceased' => 0]);
8f32b005 911 $this->assertFalse(array_key_exists($c2['id'], $result['values']));
912 }
6a488035 913
c490a46a 914 /**
381fa321 915 * Test that sort works - old syntax.
c490a46a 916 */
00be9182 917 public function testGetSort() {
f6722559 918 $c1 = $this->callAPISuccess($this->_entity, 'create', $this->_params);
46312f7d 919 $c2 = $this->callAPISuccess($this->_entity, 'create', [
92915c55
TO
920 'first_name' => 'bb',
921 'last_name' => 'ccc',
922 'contact_type' => 'Individual',
46312f7d 923 ]);
924 $result = $this->callAPISuccess($this->_entity, 'get', [
5896d037
TO
925 'sort' => 'first_name ASC',
926 'return.first_name' => 1,
927 'sequential' => 1,
928 'rowCount' => 1,
c8747697 929 'contact_type' => 'Individual',
46312f7d 930 ]);
6a488035
TO
931
932 $this->assertEquals('abc1', $result['values'][0]['first_name']);
46312f7d 933 $result = $this->callAPISuccess($this->_entity, 'get', [
f6722559 934 'sort' => 'first_name DESC',
935 'return.first_name' => 1,
936 'sequential' => 1,
937 'rowCount' => 1,
46312f7d 938 ]);
6a488035
TO
939 $this->assertEquals('bb', $result['values'][0]['first_name']);
940
46312f7d 941 $this->callAPISuccess($this->_entity, 'delete', ['id' => $c1['id']]);
942 $this->callAPISuccess($this->_entity, 'delete', ['id' => $c2['id']]);
6a488035 943 }
5896d037 944
9178793e 945 /**
946 * Test the like operator works for Contact.get
947 *
948 * @throws \CRM_Core_Exception
949 */
950 public function testGetEmailLike() {
951 $this->individualCreate();
952 $this->callAPISuccessGetCount('Contact', ['email' => ['LIKE' => 'an%']], 1);
953 $this->callAPISuccessGetCount('Contact', ['email' => ['LIKE' => 'ab%']], 0);
954 }
955
d424ffde 956 /**
381fa321 957 * Test that we can retrieve contacts using array syntax.
958 *
959 * I.e 'id' => array('IN' => array('3,4')).
46312f7d 960 *
2d932085 961 * @param int $version
46312f7d 962 *
2d932085 963 * @dataProvider versionThreeAndFour
d424ffde 964 */
2d932085
CW
965 public function testGetINIDArray($version) {
966 $this->_apiversion = $version;
78c0bfc0 967 $c1 = $this->callAPISuccess($this->_entity, 'create', $this->_params);
46312f7d 968 $c2 = $this->callAPISuccess($this->_entity, 'create', [
92915c55
TO
969 'first_name' => 'bb',
970 'last_name' => 'ccc',
971 'contact_type' => 'Individual',
46312f7d 972 ]);
973 $c3 = $this->callAPISuccess($this->_entity, 'create', [
92915c55
TO
974 'first_name' => 'hh',
975 'last_name' => 'll',
976 'contact_type' => 'Individual',
46312f7d 977 ]);
978 $result = $this->callAPISuccess($this->_entity, 'get', ['id' => ['IN' => [$c1['id'], $c3['id']]]]);
78c0bfc0 979 $this->assertEquals(2, $result['count']);
46312f7d 980 $this->assertEquals([$c1['id'], $c3['id']], array_keys($result['values']));
981 $this->callAPISuccess($this->_entity, 'delete', ['id' => $c1['id']]);
982 $this->callAPISuccess($this->_entity, 'delete', ['id' => $c2['id']]);
983 $this->callAPISuccess($this->_entity, 'delete', ['id' => $c3['id']]);
78c0bfc0 984 }
5896d037 985
d424ffde 986 /**
381fa321 987 * Test variants on deleted behaviour.
6a488035 988 */
00be9182 989 public function testGetDeleted() {
6a488035 990 $params = $this->_params;
f6722559 991 $contact1 = $this->callAPISuccess('contact', 'create', $params);
6a488035
TO
992 $params['is_deleted'] = 1;
993 $params['last_name'] = 'bcd';
f6722559 994 $contact2 = $this->callAPISuccess('contact', 'create', $params);
46312f7d 995 $countActive = $this->callAPISuccess('contact', 'getcount', [
c8747697 996 'showAll' => 'active',
997 'contact_type' => 'Individual',
46312f7d 998 ]);
999 $countAll = $this->callAPISuccess('contact', 'getcount', ['showAll' => 'all', 'contact_type' => 'Individual']);
1000 $countTrash = $this->callAPISuccess('contact', 'getcount', ['showAll' => 'trash', 'contact_type' => 'Individual']);
1001 $countDefault = $this->callAPISuccess('contact', 'getcount', ['contact_type' => 'Individual']);
1002 $countDeleted = $this->callAPISuccess('contact', 'getcount', [
c8747697 1003 'contact_type' => 'Individual',
f6722559 1004 'contact_is_deleted' => 1,
46312f7d 1005 ]);
1006 $countNotDeleted = $this->callAPISuccess('contact', 'getcount', [
f6722559 1007 'contact_is_deleted' => 0,
c8747697 1008 'contact_type' => 'Individual',
46312f7d 1009 ]);
1010 $this->callAPISuccess('contact', 'delete', ['id' => $contact1['id']]);
1011 $this->callAPISuccess('contact', 'delete', ['id' => $contact2['id']]);
c8747697 1012 $this->assertEquals(1, $countNotDeleted, 'contact_is_deleted => 0 is respected');
fe482240
EM
1013 $this->assertEquals(1, $countActive);
1014 $this->assertEquals(1, $countTrash);
1015 $this->assertEquals(2, $countAll);
1016 $this->assertEquals(1, $countDeleted);
c8747697 1017 $this->assertEquals(1, $countDefault, 'Only active by default in line');
6a488035 1018 }
c490a46a
CW
1019
1020 /**
381fa321 1021 * Test that sort works - new syntax.
46312f7d 1022 *
2d932085 1023 * @param int $version
46312f7d 1024 *
2d932085 1025 * @dataProvider versionThreeAndFour
c490a46a 1026 */
2d932085
CW
1027 public function testGetSortNewSyntax($version) {
1028 $this->_apiversion = $version;
5896d037 1029 $c1 = $this->callAPISuccess($this->_entity, 'create', $this->_params);
46312f7d 1030 $c2 = $this->callAPISuccess($this->_entity, 'create', [
92915c55
TO
1031 'first_name' => 'bb',
1032 'last_name' => 'ccc',
1033 'contact_type' => 'Individual',
46312f7d 1034 ]);
1035 $result = $this->callAPISuccess($this->_entity, 'getvalue', [
6a488035 1036 'return' => 'first_name',
c8747697 1037 'contact_type' => 'Individual',
46312f7d 1038 'options' => [
5896d037
TO
1039 'limit' => 1,
1040 'sort' => 'first_name',
46312f7d 1041 ],
1042 ]);
c8747697 1043 $this->assertEquals('abc1', $result);
6a488035 1044
46312f7d 1045 $result = $this->callAPISuccess($this->_entity, 'getvalue', [
5896d037 1046 'return' => 'first_name',
c8747697 1047 'contact_type' => 'Individual',
46312f7d 1048 'options' => [
5896d037
TO
1049 'limit' => 1,
1050 'sort' => 'first_name DESC',
46312f7d 1051 ],
1052 ]);
6a488035
TO
1053 $this->assertEquals('bb', $result);
1054
46312f7d 1055 $this->callAPISuccess($this->_entity, 'delete', ['id' => $c1['id']]);
1056 $this->callAPISuccess($this->_entity, 'delete', ['id' => $c2['id']]);
6a488035 1057 }
c490a46a 1058
c4bc3d5a
JV
1059 /**
1060 * Test sort and limit for chained relationship get.
1061 *
1062 * https://issues.civicrm.org/jira/browse/CRM-15983
2d932085 1063 * @param int $version
46312f7d 1064 *
2d932085 1065 * @dataProvider versionThreeAndFour
c4bc3d5a 1066 */
2d932085
CW
1067 public function testSortLimitChainedRelationshipGetCRM15983($version) {
1068 $this->_apiversion = $version;
c4bc3d5a 1069 // Some contact
46312f7d 1070 $create_result_1 = $this->callAPISuccess('contact', 'create', [
c4bc3d5a
JV
1071 'first_name' => 'Jules',
1072 'last_name' => 'Smos',
1073 'contact_type' => 'Individual',
46312f7d 1074 ]);
c4bc3d5a
JV
1075
1076 // Create another contact with two relationships.
46312f7d 1077 $create_params = [
c4bc3d5a
JV
1078 'first_name' => 'Jos',
1079 'last_name' => 'Smos',
1080 'contact_type' => 'Individual',
46312f7d 1081 'api.relationship.create' => [
1082 [
c4bc3d5a
JV
1083 'contact_id_a' => '$value.id',
1084 'contact_id_b' => $create_result_1['id'],
1085 // spouse of:
1086 'relationship_type_id' => 2,
1087 'start_date' => '2005-01-12',
1088 'end_date' => '2006-01-11',
1089 'description' => 'old',
46312f7d 1090 ],
1091 [
c4bc3d5a
JV
1092 'contact_id_a' => '$value.id',
1093 'contact_id_b' => $create_result_1['id'],
1094 // spouse of (was married twice :))
1095 'relationship_type_id' => 2,
1096 'start_date' => '2006-07-01',
1097 'end_date' => '2010-07-01',
1098 'description' => 'new',
46312f7d 1099 ],
1100 ],
1101 ];
c4bc3d5a
JV
1102 $create_result = $this->callAPISuccess('contact', 'create', $create_params);
1103
1104 // Try to retrieve the contact and the most recent relationship.
46312f7d 1105 $get_params = [
c4bc3d5a
JV
1106 'sequential' => 1,
1107 'id' => $create_result['id'],
46312f7d 1108 'api.relationship.get' => [
c4bc3d5a 1109 'contact_id_a' => '$value.id',
46312f7d 1110 'options' => [
c4bc3d5a
JV
1111 'limit' => '1',
1112 'sort' => 'start_date DESC',
46312f7d 1113 ],
1114 ],
1115 ];
c4bc3d5a
JV
1116 $get_result = $this->callAPISuccess('contact', 'getsingle', $get_params);
1117
1118 // Clean up.
46312f7d 1119 $this->callAPISuccess('contact', 'delete', [
c4bc3d5a 1120 'id' => $create_result['id'],
46312f7d 1121 ]);
c4bc3d5a
JV
1122
1123 // Assert.
1124 $this->assertEquals(1, $get_result['api.relationship.get']['count']);
1125 $this->assertEquals('new', $get_result['api.relationship.get']['values'][0]['description']);
1126 }
1127
c490a46a 1128 /**
381fa321 1129 * Test apostrophe works in get & create.
46312f7d 1130 *
2d932085 1131 * @param int $version
46312f7d 1132 *
2d932085 1133 * @dataProvider versionThreeAndFour
6a488035 1134 */
2d932085
CW
1135 public function testGetApostropheCRM10857($version) {
1136 $this->_apiversion = $version;
46312f7d 1137 $params = array_merge($this->_params, ['last_name' => "O'Connor"]);
4b58ed3b 1138 $this->callAPISuccess($this->_entity, 'create', $params);
46312f7d 1139 $result = $this->callAPISuccess($this->_entity, 'getsingle', [
6a488035
TO
1140 'last_name' => "O'Connor",
1141 'sequential' => 1,
46312f7d 1142 ]);
d03a02d9 1143 $this->assertEquals("O'Connor", $result['last_name']);
1144 }
1145
1146 /**
1147 * Test between accepts zero.
1148 *
1149 * In the past it incorrectly required !empty.
46312f7d 1150 *
2d932085 1151 * @param int $version
46312f7d 1152 *
2d932085 1153 * @dataProvider versionThreeAndFour
d03a02d9 1154 */
2d932085
CW
1155 public function testGetBetweenZeroWorks($version) {
1156 $this->_apiversion = $version;
d03a02d9 1157 $this->callAPISuccess($this->_entity, 'get', [
1158 'contact_id' => ['BETWEEN' => [0, 9]],
1159 ]);
1160 $this->callAPISuccess($this->_entity, 'get', [
1161 'contact_id' => [
1162 'BETWEEN' => [
1163 (0 - 9),
1164 0,
1165 ],
1166 ],
1167 ]);
6a488035
TO
1168 }
1169
54e389ac 1170 /**
1171 * Test retrieval by addressee id.
2d932085 1172 * V3 only - the "skip_greeting_processing" param is not currently in v4
54e389ac 1173 */
1174 public function testGetByAddresseeID() {
1175 $individual1ID = $this->individualCreate([
1176 'skip_greeting_processing' => 1,
1177 'addressee_id' => 'null',
1178 'email_greeting_id' => 'null',
39b959db 1179 'postal_greeting_id' => 'null',
54e389ac 1180 ]);
1181 $individual2ID = $this->individualCreate();
1182
1183 $this->assertEquals($individual1ID,
1184 $this->callAPISuccessGetValue('Contact', ['contact_type' => 'Individual', 'addressee_id' => ['IS NULL' => 1], 'return' => 'id'])
1185 );
1186 $this->assertEquals($individual1ID,
1187 $this->callAPISuccessGetValue('Contact', ['contact_type' => 'Individual', 'email_greeting_id' => ['IS NULL' => 1], 'return' => 'id'])
1188 );
1189 $this->assertEquals($individual1ID,
1190 $this->callAPISuccessGetValue('Contact', ['contact_type' => 'Individual', 'postal_greeting_id' => ['IS NULL' => 1], 'return' => 'id'])
1191 );
1192
1193 $this->assertEquals($individual2ID,
1194 $this->callAPISuccessGetValue('Contact', ['contact_type' => 'Individual', 'addressee_id' => ['NOT NULL' => 1], 'return' => 'id'])
1195 );
1196 }
1197
6a488035 1198 /**
381fa321 1199 * Check with complete array + custom field.
1200 *
6a488035
TO
1201 * Note that the test is written on purpose without any
1202 * variables specific to participant so it can be replicated into other entities
1203 * and / or moved to the automated test suite
1204 */
00be9182 1205 public function testGetWithCustom() {
6a488035
TO
1206 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
1207
1208 $params = $this->_params;
1209 $params['custom_' . $ids['custom_field_id']] = "custom string";
5c49fee0 1210 $description = "This demonstrates setting a custom field through the API.";
6a488035 1211 $subfile = "CustomFieldGet";
f6722559 1212 $result = $this->callAPISuccess($this->_entity, 'create', $params);
6a488035 1213
46312f7d 1214 $check = $this->callAPIAndDocument($this->_entity, 'get', [
92915c55
TO
1215 'return.custom_' . $ids['custom_field_id'] => 1,
1216 'id' => $result['id'],
46312f7d 1217 ], __FUNCTION__, __FILE__, $description, $subfile);
6a488035 1218
4b58ed3b 1219 $this->assertEquals("custom string", $check['values'][$check['id']]['custom_' . $ids['custom_field_id']]);
f6722559 1220 $fields = ($this->callAPISuccess('contact', 'getfields', $params));
6a488035
TO
1221 $this->assertTrue(is_array($fields['values']['custom_' . $ids['custom_field_id']]));
1222 $this->customFieldDelete($ids['custom_field_id']);
1223 $this->customGroupDelete($ids['custom_group_id']);
1224 }
c490a46a 1225
697aad03 1226 /**
1227 * Tests that using 'return' with a custom field not of type contact does not inappropriately filter.
1228 *
1229 * https://lab.civicrm.org/dev/core/issues/1025
1230 *
1231 * @throws \CRM_Core_Exception
1232 */
1233 public function testGetWithCustomOfActivityType() {
1234 $this->createCustomGroupWithFieldOfType(['extends' => 'Activity']);
1235 $this->createCustomGroupWithFieldOfType(['extends' => 'Contact'], 'text', 'contact_');
1236 $contactID = $this->individualCreate();
1237 $this->callAPISuccessGetSingle('Contact', ['id' => $contactID, 'return' => ['external_identifier', $this->getCustomFieldName('contact_text')]]);
1238 }
1239
c490a46a 1240 /**
381fa321 1241 * Check with complete array + custom field.
1242 *
c490a46a
CW
1243 * Note that the test is written on purpose without any
1244 * variables specific to participant so it can be replicated into other entities
1245 * and / or moved to the automated test suite
1246 */
00be9182 1247 public function testGetWithCustomReturnSyntax() {
6a488035
TO
1248 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
1249
1250 $params = $this->_params;
1251 $params['custom_' . $ids['custom_field_id']] = "custom string";
5c49fee0 1252 $description = "This demonstrates setting a custom field through the API.";
6a488035 1253 $subfile = "CustomFieldGetReturnSyntaxVariation";
f6722559 1254 $result = $this->callAPISuccess($this->_entity, 'create', $params);
46312f7d 1255 $params = ['return' => 'custom_' . $ids['custom_field_id'], 'id' => $result['id']];
f6722559 1256 $check = $this->callAPIAndDocument($this->_entity, 'get', $params, __FUNCTION__, __FILE__, $description, $subfile);
6a488035 1257
43ef1263 1258 $this->assertEquals("custom string", $check['values'][$check['id']]['custom_' . $ids['custom_field_id']]);
6a488035
TO
1259 $this->customFieldDelete($ids['custom_field_id']);
1260 $this->customGroupDelete($ids['custom_group_id']);
1261 }
1262
43ef1263 1263 /**
66670e4d 1264 * Check that address name, ID is returned if required.
43ef1263 1265 */
66670e4d 1266 public function testGetReturnAddress() {
43ef1263 1267 $contactID = $this->individualCreate();
46312f7d 1268 $result = $this->callAPISuccess('address', 'create', [
92915c55
TO
1269 'contact_id' => $contactID,
1270 'address_name' => 'My house',
1271 'location_type_id' => 'Home',
1272 'street_address' => '1 my road',
46312f7d 1273 ]);
66670e4d 1274 $addressID = $result['id'];
1275
46312f7d 1276 $result = $this->callAPISuccessGetSingle('contact', [
66670e4d 1277 'return' => 'address_name, street_address, address_id',
92915c55 1278 'id' => $contactID,
46312f7d 1279 ]);
66670e4d 1280 $this->assertEquals($addressID, $result['address_id']);
43ef1263
EM
1281 $this->assertEquals('1 my road', $result['street_address']);
1282 $this->assertEquals('My house', $result['address_name']);
1283
1284 }
1285
701a69da 1286 /**
1287 * Test group filter syntaxes.
1288 */
00be9182 1289 public function testGetGroupIDFromContact() {
5896d037 1290 $groupId = $this->groupCreate();
46312f7d 1291 $params = [
6a488035
TO
1292 'email' => 'man2@yahoo.com',
1293 'contact_type' => 'Individual',
1294 'location_type_id' => 1,
46312f7d 1295 'api.group_contact.create' => ['group_id' => $groupId],
1296 ];
6a488035 1297
4b58ed3b 1298 $this->callAPISuccess('contact', 'create', $params);
6a488035 1299 // testing as integer
46312f7d 1300 $params = [
d0aa0e47 1301 'filter.group_id' => $groupId,
6a488035 1302 'contact_type' => 'Individual',
46312f7d 1303 ];
d0aa0e47 1304 $result = $this->callAPISuccess('contact', 'get', $params);
6a488035
TO
1305 $this->assertEquals(1, $result['count']);
1306 // group 26 doesn't exist, but we can still search contacts in it.
46312f7d 1307 $params = [
d0aa0e47 1308 'filter.group_id' => 26,
6a488035 1309 'contact_type' => 'Individual',
46312f7d 1310 ];
4b58ed3b 1311 $this->callAPISuccess('contact', 'get', $params);
6a488035 1312 // testing as string
46312f7d 1313 $params = [
d0aa0e47 1314 'filter.group_id' => "$groupId, 26",
6a488035 1315 'contact_type' => 'Individual',
46312f7d 1316 ];
d0aa0e47 1317 $result = $this->callAPISuccess('contact', 'get', $params);
6a488035 1318 $this->assertEquals(1, $result['count']);
46312f7d 1319 $params = [
d0aa0e47 1320 'filter.group_id' => "26,27",
6a488035 1321 'contact_type' => 'Individual',
46312f7d 1322 ];
4b58ed3b 1323 $this->callAPISuccess('contact', 'get', $params);
6a488035
TO
1324
1325 // testing as string
46312f7d 1326 $params = [
1327 'filter.group_id' => [$groupId, 26],
6a488035 1328 'contact_type' => 'Individual',
46312f7d 1329 ];
d0aa0e47 1330 $result = $this->callAPISuccess('contact', 'get', $params);
6a488035
TO
1331 $this->assertEquals(1, $result['count']);
1332
1333 //test in conjunction with other criteria
46312f7d 1334 $params = [
1335 'filter.group_id' => [$groupId, 26],
6a488035 1336 'contact_type' => 'Organization',
46312f7d 1337 ];
6c6e6187 1338 $this->callAPISuccess('contact', 'get', $params);
46312f7d 1339 $params = [
1340 'filter.group_id' => [26, 27],
6a488035 1341 'contact_type' => 'Individual',
46312f7d 1342 ];
f6722559 1343 $result = $this->callAPISuccess('contact', 'get', $params);
4b58ed3b 1344 $this->assertEquals(0, $result['count']);
6a488035
TO
1345 }
1346
1347 /**
381fa321 1348 * Verify that attempt to create individual contact with two chained websites succeeds.
6a488035 1349 */
00be9182 1350 public function testCreateIndividualWithContributionDottedSyntax() {
5c49fee0 1351 $description = "This demonstrates the syntax to create 2 chained entities.";
5896d037 1352 $subFile = "ChainTwoWebsites";
46312f7d 1353 $params = [
6a488035
TO
1354 'first_name' => 'abc3',
1355 'last_name' => 'xyz3',
1356 'contact_type' => 'Individual',
1357 'email' => 'man3@yahoo.com',
46312f7d 1358 'api.contribution.create' => [
6a488035
TO
1359 'receive_date' => '2010-01-01',
1360 'total_amount' => 100.00,
5896d037 1361 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
1362 'payment_instrument_id' => 1,
1363 'non_deductible_amount' => 10.00,
1364 'fee_amount' => 50.00,
1365 'net_amount' => 90.00,
1366 'trxn_id' => 15345,
1367 'invoice_id' => 67990,
1368 'source' => 'SSF',
1369 'contribution_status_id' => 1,
25ac4ffa 1370 'skipCleanMoney' => 1,
46312f7d 1371 ],
1372 'api.website.create' => [
6a488035 1373 'url' => "http://civicrm.org",
46312f7d 1374 ],
1375 'api.website.create.2' => [
6a488035 1376 'url' => "http://chained.org",
46312f7d 1377 ],
1378 ];
6a488035 1379
4b58ed3b 1380 $result = $this->callAPIAndDocument('Contact', 'create', $params, __FUNCTION__, __FILE__, $description, $subFile);
6a488035 1381
f6722559 1382 // checking child function result not covered in callAPIAndDocument
1383 $this->assertAPISuccess($result['values'][$result['id']]['api.website.create']);
fe482240
EM
1384 $this->assertEquals("http://chained.org", $result['values'][$result['id']]['api.website.create.2']['values'][0]['url']);
1385 $this->assertEquals("http://civicrm.org", $result['values'][$result['id']]['api.website.create']['values'][0]['url']);
6a488035
TO
1386
1387 // delete the contact
f6722559 1388 $this->callAPISuccess('contact', 'delete', $result);
6a488035
TO
1389 }
1390
1391 /**
381fa321 1392 * Verify that attempt to create individual contact with chained contribution and website succeeds.
6a488035 1393 */
00be9182 1394 public function testCreateIndividualWithContributionChainedArrays() {
46312f7d 1395 $params = [
6a488035
TO
1396 'first_name' => 'abc3',
1397 'last_name' => 'xyz3',
1398 'contact_type' => 'Individual',
1399 'email' => 'man3@yahoo.com',
46312f7d 1400 'api.contribution.create' => [
6a488035
TO
1401 'receive_date' => '2010-01-01',
1402 'total_amount' => 100.00,
5896d037 1403 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
1404 'payment_instrument_id' => 1,
1405 'non_deductible_amount' => 10.00,
1406 'fee_amount' => 50.00,
1407 'net_amount' => 90.00,
1408 'trxn_id' => 12345,
1409 'invoice_id' => 67890,
1410 'source' => 'SSF',
1411 'contribution_status_id' => 1,
25ac4ffa 1412 'skipCleanMoney' => 1,
46312f7d 1413 ],
1414 'api.website.create' => [
1415 [
6a488035 1416 'url' => "http://civicrm.org",
46312f7d 1417 ],
1418 [
6a488035
TO
1419 'url' => "http://chained.org",
1420 'website_type_id' => 2,
46312f7d 1421 ],
1422 ],
1423 ];
6a488035 1424
5c49fee0 1425 $description = "Demonstrates creating two websites as an array.";
5896d037
TO
1426 $subfile = "ChainTwoWebsitesSyntax2";
1427 $result = $this->callAPIAndDocument('Contact', 'create', $params, __FUNCTION__, __FILE__, $description, $subfile);
f6722559 1428
f6722559 1429 // the callAndDocument doesn't check the chained call
fe482240
EM
1430 $this->assertEquals(0, $result['values'][$result['id']]['api.website.create'][0]['is_error']);
1431 $this->assertEquals("http://chained.org", $result['values'][$result['id']]['api.website.create'][1]['values'][0]['url']);
1432 $this->assertEquals("http://civicrm.org", $result['values'][$result['id']]['api.website.create'][0]['values'][0]['url']);
6a488035 1433
f6722559 1434 $this->callAPISuccess('contact', 'delete', $result);
6a488035
TO
1435 }
1436
92d270fd
JV
1437 /**
1438 * Test for direction when chaining relationships.
1439 *
1440 * https://issues.civicrm.org/jira/browse/CRM-16084
2d932085 1441 * @param int $version
46312f7d 1442 *
2d932085 1443 * @dataProvider versionThreeAndFour
92d270fd 1444 */
2d932085
CW
1445 public function testDirectionChainingRelationshipsCRM16084($version) {
1446 $this->_apiversion = $version;
92d270fd 1447 // Some contact, called Jules.
46312f7d 1448 $create_result_1 = $this->callAPISuccess('contact', 'create', [
92d270fd
JV
1449 'first_name' => 'Jules',
1450 'last_name' => 'Smos',
1451 'contact_type' => 'Individual',
46312f7d 1452 ]);
92d270fd
JV
1453
1454 // Another contact: Jos, child of Jules.
46312f7d 1455 $create_params = [
92d270fd
JV
1456 'first_name' => 'Jos',
1457 'last_name' => 'Smos',
1458 'contact_type' => 'Individual',
46312f7d 1459 'api.relationship.create' => [
1460 [
92d270fd
JV
1461 'contact_id_a' => '$value.id',
1462 'contact_id_b' => $create_result_1['id'],
1463 // child of
1464 'relationship_type_id' => 1,
46312f7d 1465 ],
1466 ],
1467 ];
92d270fd
JV
1468 $create_result_2 = $this->callAPISuccess('contact', 'create', $create_params);
1469
1470 // Mia is the child of Jos.
46312f7d 1471 $create_params = [
92d270fd
JV
1472 'first_name' => 'Mia',
1473 'last_name' => 'Smos',
1474 'contact_type' => 'Individual',
46312f7d 1475 'api.relationship.create' => [
1476 [
92d270fd
JV
1477 'contact_id_a' => '$value.id',
1478 'contact_id_b' => $create_result_2['id'],
1479 // child of
1480 'relationship_type_id' => 1,
46312f7d 1481 ],
1482 ],
1483 ];
92d270fd
JV
1484 $create_result_3 = $this->callAPISuccess('contact', 'create', $create_params);
1485
1486 // Get Jos and his children.
46312f7d 1487 $get_params = [
92d270fd
JV
1488 'sequential' => 1,
1489 'id' => $create_result_2['id'],
46312f7d 1490 'api.relationship.get' => [
92d270fd
JV
1491 'contact_id_b' => '$value.id',
1492 'relationship_type_id' => 1,
46312f7d 1493 ],
1494 ];
92d270fd
JV
1495 $get_result = $this->callAPISuccess('contact', 'getsingle', $get_params);
1496
1497 // Clean up first.
46312f7d 1498 $this->callAPISuccess('contact', 'delete', [
92d270fd 1499 'id' => $create_result_1['id'],
46312f7d 1500 ]);
1501 $this->callAPISuccess('contact', 'delete', [
92d270fd 1502 'id' => $create_result_2['id'],
46312f7d 1503 ]);
92d270fd
JV
1504
1505 // Assert.
1506 $this->assertEquals(1, $get_result['api.relationship.get']['count']);
1507 $this->assertEquals($create_result_3['id'], $get_result['api.relationship.get']['values'][0]['contact_id_a']);
1508 }
1509
6a488035 1510 /**
fe482240 1511 * Verify that attempt to create individual contact with first, and last names and email succeeds.
6a488035 1512 */
00be9182 1513 public function testCreateIndividualWithNameEmail() {
46312f7d 1514 $params = [
6a488035
TO
1515 'first_name' => 'abc3',
1516 'last_name' => 'xyz3',
1517 'contact_type' => 'Individual',
1518 'email' => 'man3@yahoo.com',
46312f7d 1519 ];
6a488035 1520
f6722559 1521 $contact = $this->callAPISuccess('contact', 'create', $params);
6a488035 1522
f6722559 1523 $this->callAPISuccess('contact', 'delete', $contact);
6a488035 1524 }
5896d037 1525
6a488035 1526 /**
eceb18cc 1527 * Verify that attempt to create individual contact with no data fails.
6a488035 1528 */
00be9182 1529 public function testCreateIndividualWithOutNameEmail() {
46312f7d 1530 $params = [
6a488035 1531 'contact_type' => 'Individual',
46312f7d 1532 ];
4b58ed3b 1533 $this->callAPIFailure('contact', 'create', $params);
6a488035 1534 }
5896d037 1535
6a488035 1536 /**
fe482240 1537 * Test create individual contact with first &last names, email and location type succeeds.
6a488035 1538 */
00be9182 1539 public function testCreateIndividualWithNameEmailLocationType() {
46312f7d 1540 $params = [
6a488035
TO
1541 'first_name' => 'abc4',
1542 'last_name' => 'xyz4',
1543 'email' => 'man4@yahoo.com',
1544 'contact_type' => 'Individual',
1545 'location_type_id' => 1,
46312f7d 1546 ];
f6722559 1547 $result = $this->callAPISuccess('contact', 'create', $params);
6a488035 1548
46312f7d 1549 $this->callAPISuccess('contact', 'delete', ['id' => $result['id']]);
6a488035
TO
1550 }
1551
1552 /**
fe482240 1553 * Verify that when changing employers the old employer relationship becomes inactive.
6a488035 1554 */
00be9182 1555 public function testCreateIndividualWithEmployer() {
6a488035
TO
1556 $employer = $this->organizationCreate();
1557 $employer2 = $this->organizationCreate();
1558
46312f7d 1559 $params = [
5896d037
TO
1560 'email' => 'man4@yahoo.com',
1561 'contact_type' => 'Individual',
1562 'employer_id' => $employer,
46312f7d 1563 ];
6a488035 1564
f6722559 1565 $result = $this->callAPISuccess('contact', 'create', $params);
46312f7d 1566 $relationships = $this->callAPISuccess('relationship', 'get', [
6a488035
TO
1567 'contact_id_a' => $result['id'],
1568 'sequential' => 1,
46312f7d 1569 ]);
6a488035
TO
1570
1571 $this->assertEquals($employer, $relationships['values'][0]['contact_id_b']);
1572
1573 // Add more random relationships to make the test more realistic
46312f7d 1574 foreach (['Employee of', 'Volunteer for'] as $relationshipType) {
4b58ed3b 1575 $relTypeId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType', $relationshipType, 'id', 'name_a_b');
46312f7d 1576 $this->callAPISuccess('relationship', 'create', [
6a488035
TO
1577 'contact_id_a' => $result['id'],
1578 'contact_id_b' => $this->organizationCreate(),
1579 'is_active' => 1,
1580 'relationship_type_id' => $relTypeId,
46312f7d 1581 ]);
6c6e6187 1582 }
6a488035
TO
1583
1584 // Add second employer
1585 $params['employer_id'] = $employer2;
1586 $params['id'] = $result['id'];
f6722559 1587 $result = $this->callAPISuccess('contact', 'create', $params);
6a488035 1588
46312f7d 1589 $relationships = $this->callAPISuccess('relationship', 'get', [
6a488035
TO
1590 'contact_id_a' => $result['id'],
1591 'sequential' => 1,
1592 'is_active' => 0,
46312f7d 1593 ]);
6a488035
TO
1594
1595 $this->assertEquals($employer, $relationships['values'][0]['contact_id_b']);
1596 }
1597
1598 /**
fe482240 1599 * Verify that attempt to create household contact with details succeeds.
6a488035 1600 */
00be9182 1601 public function testCreateHouseholdDetails() {
46312f7d 1602 $params = [
6a488035
TO
1603 'household_name' => 'abc8\'s House',
1604 'nick_name' => 'x House',
1605 'email' => 'man8@yahoo.com',
1606 'contact_type' => 'Household',
46312f7d 1607 ];
6a488035 1608
f6722559 1609 $contact = $this->callAPISuccess('contact', 'create', $params);
1610
f6722559 1611 $this->callAPISuccess('contact', 'delete', $contact);
6a488035 1612 }
5896d037 1613
6a488035 1614 /**
381fa321 1615 * Verify that attempt to create household contact with inadequate details fails.
6a488035 1616 */
00be9182 1617 public function testCreateHouseholdInadequateDetails() {
46312f7d 1618 $params = [
6a488035
TO
1619 'nick_name' => 'x House',
1620 'email' => 'man8@yahoo.com',
1621 'contact_type' => 'Household',
46312f7d 1622 ];
4b58ed3b 1623 $this->callAPIFailure('contact', 'create', $params);
6a488035
TO
1624 }
1625
6a488035 1626 /**
381fa321 1627 * Verify successful update of individual contact.
6a488035 1628 */
00be9182 1629 public function testUpdateIndividualWithAll() {
ae8bd424 1630 $contactID = $this->individualCreate();
6a488035 1631
ae8bd424 1632 $params = [
1633 'id' => $contactID,
6a488035
TO
1634 'first_name' => 'abcd',
1635 'contact_type' => 'Individual',
1636 'nick_name' => 'This is nickname first',
1637 'do_not_email' => '1',
1638 'do_not_phone' => '1',
1639 'do_not_mail' => '1',
1640 'do_not_trade' => '1',
1641 'legal_identifier' => 'ABC23853ZZ2235',
1642 'external_identifier' => '1928837465',
1643 'image_URL' => 'http://some.url.com/image.jpg',
1644 'home_url' => 'http://www.example.org',
ae8bd424 1645 ];
43ef1263 1646
4b58ed3b 1647 $this->callAPISuccess('Contact', 'Update', $params);
f6722559 1648 $getResult = $this->callAPISuccess('Contact', 'Get', $params);
6a488035
TO
1649 unset($params['contact_id']);
1650 //Todo - neither API v2 or V3 are testing for home_url - not sure if it is being set.
4b58ed3b 1651 //reducing this test partially back to api v2 level to get it through
6a488035
TO
1652 unset($params['home_url']);
1653 foreach ($params as $key => $value) {
ae8bd424 1654 $this->assertEquals($value, $getResult['values'][$contactID][$key]);
6a488035 1655 }
6a488035
TO
1656 }
1657
1658 /**
eceb18cc 1659 * Verify successful update of organization contact.
ae8bd424 1660 *
1661 * @throws \Exception
6a488035 1662 */
00be9182 1663 public function testUpdateOrganizationWithAll() {
ae8bd424 1664 $contactID = $this->organizationCreate();
6a488035 1665
ae8bd424 1666 $params = [
1667 'id' => $contactID,
6a488035
TO
1668 'organization_name' => 'WebAccess India Pvt Ltd',
1669 'legal_name' => 'WebAccess',
1670 'sic_code' => 'ABC12DEF',
1671 'contact_type' => 'Organization',
ae8bd424 1672 ];
6a488035 1673
4b58ed3b 1674 $this->callAPISuccess('Contact', 'Update', $params);
ae8bd424 1675 $this->getAndCheck($params, $contactID, 'Contact');
6a488035
TO
1676 }
1677
4099a9c5
AP
1678 /**
1679 * Test merging 2 organizations.
1680 *
1681 * CRM-20421: This test make sure that inherited memberships are deleted upon merging organization.
1682 */
1683 public function testMergeOrganizations() {
aefc291e 1684 $organizationID1 = $this->organizationCreate([], 0);
46312f7d 1685 $organizationID2 = $this->organizationCreate([], 1);
1686 $contact = $this->callAPISuccess('contact', 'create', array_merge($this->_params, [
39b959db 1687 'employer_id' => $organizationID1,
46312f7d 1688 ]));
4099a9c5
AP
1689 $contact = $contact["values"][$contact["id"]];
1690
1691 $membershipType = $this->createEmployerOfMembership();
46312f7d 1692 $membershipParams = [
4099a9c5
AP
1693 'membership_type_id' => $membershipType["id"],
1694 'contact_id' => $organizationID1,
1695 'start_date' => "01/01/2015",
1696 'join_date' => "01/01/2010",
1697 'end_date' => "12/31/2015",
46312f7d 1698 ];
4099a9c5
AP
1699 $ownermembershipid = $this->contactMembershipCreate($membershipParams);
1700
46312f7d 1701 $contactmembership = $this->callAPISuccess("membership", "getsingle", [
4099a9c5 1702 "contact_id" => $contact["id"],
46312f7d 1703 ]);
4099a9c5
AP
1704
1705 $this->assertEquals($ownermembershipid, $contactmembership["owner_membership_id"], "Contact membership must be inherited from Organization");
1706
46312f7d 1707 CRM_Dedupe_Merger::moveAllBelongings($organizationID2, $organizationID1, [
1708 "move_rel_table_memberships" => "0",
4099a9c5 1709 "move_rel_table_relationships" => "1",
46312f7d 1710 "main_details" => [
1711 "contact_id" => $organizationID2,
4099a9c5 1712 "contact_type" => "Organization",
46312f7d 1713 ],
1714 "other_details" => [
1715 "contact_id" => $organizationID1,
4099a9c5 1716 "contact_type" => "Organization",
46312f7d 1717 ],
1718 ]);
4099a9c5 1719
46312f7d 1720 $contactmembership = $this->callAPISuccess("membership", "get", [
4099a9c5 1721 "contact_id" => $contact["id"],
46312f7d 1722 ]);
4099a9c5
AP
1723
1724 $this->assertEquals(0, $contactmembership["count"], "Contact membership must be deleted after merging organization without memberships.");
1725 }
1726
aefc291e 1727 /**
1728 * Test the function that determines if 2 contacts have conflicts.
712ee28f 1729 *
1730 * @throws \Exception
aefc291e 1731 */
1732 public function testMergeGetConflicts() {
712ee28f 1733 $this->createCustomGroupWithFieldOfType();
1734 $contact1 = $this->individualCreate([
1735 'email' => 'bob@example.com',
1736 'api.address.create' => ['location_type_id' => 'work', 'street_address' => 'big office', 'city' => 'small city'],
1737 'api.address.create.2' => ['location_type_id' => 'home', 'street_address' => 'big house', 'city' => 'small city'],
1738 'external_identifier' => 'unique and special',
1739 $this->getCustomFieldName('text') => 'mummy loves me',
1740 ]);
1741 $contact2 = $this->individualCreate([
1742 'first_name' => 'different',
1743 'api.address.create.1' => ['location_type_id' => 'home', 'street_address' => 'medium house', 'city' => 'small city'],
1744 'api.address.create.2' => ['location_type_id' => 'work', 'street_address' => 'medium office', 'city' => 'small city'],
1745 'external_identifier' => 'uniquer and specialler',
ffa59d18 1746 'api.email.create' => ['location_type_id' => 'Other', 'email' => 'bob@example.com'],
712ee28f 1747 $this->getCustomFieldName('text') => 'mummy loves me more',
1748 ]);
aefc291e 1749 $conflicts = $this->callAPISuccess('Contact', 'get_merge_conflicts', ['to_keep_id' => $contact1, 'to_remove_id' => $contact2])['values'];
712ee28f 1750 $this->assertEquals([
1751 'safe' => [
1752 'conflicts' => [
1753 'contact' => [
ffa59d18 1754 'first_name' => [$contact1 => 'Anthony', $contact2 => 'different', 'title' => 'First Name'],
1755 'external_identifier' => [$contact1 => 'unique and special', $contact2 => 'uniquer and specialler', 'title' => 'External Identifier'],
1756 $this->getCustomFieldName('text') => [$contact1 => 'mummy loves me', $contact2 => 'mummy loves me more', 'title' => 'Enter text here'],
712ee28f 1757 ],
1758 'address' => [
1759 [
1760 'location_type_id' => '1',
ffa59d18 1761 'title' => 'Address 1 (Home)',
712ee28f 1762 'street_address' => [
1763 $contact1 => 'big house',
1764 $contact2 => 'medium house',
1765 ],
ffa59d18 1766 'display' => [
1767 $contact1 => "big house\nsmall city, \n",
1768 $contact2 => "medium house\nsmall city, \n",
1769 ],
712ee28f 1770 ],
1771 [
1772 'location_type_id' => '2',
1773 'street_address' => [
1774 $contact1 => 'big office',
1775 $contact2 => 'medium office',
1776 ],
ffa59d18 1777 'title' => 'Address 2 (Work)',
1778 'display' => [
1779 $contact1 => "big office\nsmall city, \n",
1780 $contact2 => "medium office\nsmall city, \n",
1781 ],
712ee28f 1782 ],
1783 ],
1784 'email' => [
1785 [
1786 'location_type_id' => '1',
1787 'email' => [
1788 $contact1 => 'bob@example.com',
1789 $contact2 => 'anthony_anderson@civicrm.org',
1790 ],
ffa59d18 1791 'title' => 'Email 1 (Home)',
1792 'display' => [
1793 $contact1 => 'bob@example.com',
1794 $contact2 => 'anthony_anderson@civicrm.org',
1795 ],
712ee28f 1796 ],
1797 ],
1798 ],
1799 ],
1800 ], $conflicts);
ffa59d18 1801
1802 $result = $this->callAPISuccess('Job', 'process_batch_merge');
1803 $defaultRuleGroupID = $this->callAPISuccessGetValue('RuleGroup', [
1804 'contact_type' => 'Individual',
1805 'used' => 'Unsupervised',
1806 'return' => 'id',
1807 'options' => ['limit' => 1],
1808 ]);
1809
1810 $duplicates = $this->callAPISuccess('Dedupe', 'getduplicates', ['rule_group_id' => $defaultRuleGroupID]);
1811 $this->assertEquals($conflicts['safe'], $duplicates['values'][0]['safe']);
aefc291e 1812 }
1813
4099a9c5 1814 private function createEmployerOfMembership() {
46312f7d 1815 $params = [
4099a9c5
AP
1816 'domain_id' => CRM_Core_Config::domainID(),
1817 'name' => 'Organization Membership',
1818 'description' => NULL,
1819 'member_of_contact_id' => 1,
1820 'financial_type_id' => 1,
1821 'minimum_fee' => 10,
1822 'duration_unit' => 'year',
1823 'duration_interval' => 1,
1824 'period_type' => 'rolling',
1825 'relationship_type_id' => 5,
1826 'relationship_direction' => 'b_a',
1827 'visibility' => 'Public',
1828 'is_active' => 1,
46312f7d 1829 ];
4099a9c5
AP
1830 $membershipType = $this->callAPISuccess('membership_type', 'create', $params);
1831 return $membershipType["values"][$membershipType["id"]];
1832 }
1833
6a488035 1834 /**
381fa321 1835 * Verify successful update of household contact.
46312f7d 1836 *
2d932085 1837 * @param int $version
46312f7d 1838 *
2d932085 1839 * @dataProvider versionThreeAndFour
6a488035 1840 */
2d932085
CW
1841 public function testUpdateHouseholdWithAll($version) {
1842 $this->_apiversion = $version;
ae8bd424 1843 $contactID = $this->householdCreate();
6a488035 1844
ae8bd424 1845 $params = [
46312f7d 1846 'id' => $contactID,
6a488035
TO
1847 'household_name' => 'ABC household',
1848 'nick_name' => 'ABC House',
1849 'contact_type' => 'Household',
ae8bd424 1850 ];
6a488035 1851
f6722559 1852 $result = $this->callAPISuccess('Contact', 'Update', $params);
6a488035 1853
ae8bd424 1854 $expected = [
43ef1263
EM
1855 'contact_type' => 'Household',
1856 'is_opt_out' => 0,
1857 'sort_name' => 'ABC household',
1858 'display_name' => 'ABC household',
1859 'nick_name' => 'ABC House',
ae8bd424 1860 ];
43ef1263 1861 $this->getAndCheck($expected, $result['id'], 'contact');
6a488035
TO
1862 }
1863
1864 /**
381fa321 1865 * Test civicrm_update() without contact type.
1866 *
1867 * Deliberately exclude contact_type as it should still cope using civicrm_api.
1868 *
1869 * CRM-7645.
46312f7d 1870 *
2d932085 1871 * @param int $version
46312f7d 1872 *
2d932085 1873 * @dataProvider versionThreeAndFour
6a488035 1874 */
2d932085
CW
1875 public function testUpdateCreateWithID($version) {
1876 $this->_apiversion = $version;
ae8bd424 1877 $contactID = $this->individualCreate();
1878 $this->callAPISuccess('Contact', 'Update', [
1879 'id' => $contactID,
6a488035
TO
1880 'first_name' => 'abcd',
1881 'last_name' => 'wxyz',
ae8bd424 1882 ]);
6a488035
TO
1883 }
1884
1885 /**
381fa321 1886 * Test civicrm_contact_delete() with no contact ID.
46312f7d 1887 *
2d932085 1888 * @param int $version
46312f7d 1889 *
2d932085 1890 * @dataProvider versionThreeAndFour
6a488035 1891 */
2d932085
CW
1892 public function testContactDeleteNoID($version) {
1893 $this->_apiversion = $version;
46312f7d 1894 $params = [
6a488035 1895 'foo' => 'bar',
46312f7d 1896 ];
4b58ed3b 1897 $this->callAPIFailure('contact', 'delete', $params);
6a488035
TO
1898 }
1899
1900 /**
381fa321 1901 * Test civicrm_contact_delete() with error.
46312f7d 1902 *
2d932085 1903 * @param int $version
46312f7d 1904 *
2d932085 1905 * @dataProvider versionThreeAndFour
6a488035 1906 */
2d932085
CW
1907 public function testContactDeleteError($version) {
1908 $this->_apiversion = $version;
46312f7d 1909 $params = ['contact_id' => 999];
4b58ed3b 1910 $this->callAPIFailure('contact', 'delete', $params);
6a488035
TO
1911 }
1912
1913 /**
381fa321 1914 * Test civicrm_contact_delete().
46312f7d 1915 *
2d932085 1916 * @param int $version
46312f7d 1917 *
2d932085 1918 * @dataProvider versionThreeAndFour
6a488035 1919 */
2d932085
CW
1920 public function testContactDelete($version) {
1921 $this->_apiversion = $version;
f6722559 1922 $contactID = $this->individualCreate();
46312f7d 1923 $params = [
5896d037 1924 'id' => $contactID,
46312f7d 1925 ];
4b58ed3b 1926 $this->callAPIAndDocument('contact', 'delete', $params, __FUNCTION__, __FILE__);
6a488035
TO
1927 }
1928
1929 /**
381fa321 1930 * Test civicrm_contact_get() return only first name.
46312f7d 1931 *
2d932085 1932 * @param int $version
46312f7d 1933 *
2d932085 1934 * @dataProvider versionThreeAndFour
6a488035 1935 */
2d932085
CW
1936 public function testContactGetRetFirst($version) {
1937 $this->_apiversion = $version;
f6722559 1938 $contact = $this->callAPISuccess('contact', 'create', $this->_params);
46312f7d 1939 $params = [
6a488035
TO
1940 'contact_id' => $contact['id'],
1941 'return_first_name' => TRUE,
1942 'sort' => 'first_name',
46312f7d 1943 ];
f6722559 1944 $result = $this->callAPISuccess('contact', 'get', $params);
4b58ed3b
EM
1945 $this->assertEquals(1, $result['count']);
1946 $this->assertEquals($contact['id'], $result['id']);
1947 $this->assertEquals('abc1', $result['values'][$contact['id']]['first_name']);
6a488035
TO
1948 }
1949
1950 /**
381fa321 1951 * Test civicrm_contact_get() return only first name & last name.
1952 *
1953 * Use comma separated string return with a space.
46312f7d 1954 *
2d932085 1955 * @param int $version
46312f7d 1956 *
2d932085 1957 * @dataProvider versionThreeAndFour
6a488035 1958 */
2d932085
CW
1959 public function testContactGetReturnFirstLast($version) {
1960 $this->_apiversion = $version;
f6722559 1961 $contact = $this->callAPISuccess('contact', 'create', $this->_params);
46312f7d 1962 $params = [
6a488035
TO
1963 'contact_id' => $contact['id'],
1964 'return' => 'first_name, last_name',
46312f7d 1965 ];
f6722559 1966 $result = $this->callAPISuccess('contact', 'getsingle', $params);
4b58ed3b
EM
1967 $this->assertEquals('abc1', $result['first_name']);
1968 $this->assertEquals('xyz1', $result['last_name']);
6a488035
TO
1969 //check that other defaults not returns
1970 $this->assertArrayNotHasKey('sort_name', $result);
46312f7d 1971 $params = [
6a488035
TO
1972 'contact_id' => $contact['id'],
1973 'return' => 'first_name,last_name',
46312f7d 1974 ];
f6722559 1975 $result = $this->callAPISuccess('contact', 'getsingle', $params);
4b58ed3b
EM
1976 $this->assertEquals('abc1', $result['first_name']);
1977 $this->assertEquals('xyz1', $result['last_name']);
6a488035
TO
1978 //check that other defaults not returns
1979 $this->assertArrayNotHasKey('sort_name', $result);
1980 }
1981
1982 /**
381fa321 1983 * Test civicrm_contact_get() return only first name & last name.
1984 *
d177a2a6 1985 * Use comma separated string return without a space
46312f7d 1986 *
2d932085 1987 * @param int $version
46312f7d 1988 *
2d932085 1989 * @dataProvider versionThreeAndFour
6a488035 1990 */
2d932085
CW
1991 public function testContactGetReturnFirstLastNoComma($version) {
1992 $this->_apiversion = $version;
f6722559 1993 $contact = $this->callAPISuccess('contact', 'create', $this->_params);
46312f7d 1994 $params = [
6a488035
TO
1995 'contact_id' => $contact['id'],
1996 'return' => 'first_name,last_name',
46312f7d 1997 ];
f6722559 1998 $result = $this->callAPISuccess('contact', 'getsingle', $params);
4b58ed3b
EM
1999 $this->assertEquals('abc1', $result['first_name']);
2000 $this->assertEquals('xyz1', $result['last_name']);
6a488035
TO
2001 //check that other defaults not returns
2002 $this->assertArrayNotHasKey('sort_name', $result);
2003 }
2004
2005 /**
381fa321 2006 * Test civicrm_contact_get() with default return properties.
6a488035
TO
2007 */
2008 public function testContactGetRetDefault() {
43ef1263 2009 $contactID = $this->individualCreate();
46312f7d 2010 $params = [
43ef1263 2011 'contact_id' => $contactID,
6a488035 2012 'sort' => 'first_name',
46312f7d 2013 ];
f6722559 2014 $result = $this->callAPISuccess('contact', 'get', $params);
43ef1263
EM
2015 $this->assertEquals($contactID, $result['values'][$contactID]['contact_id']);
2016 $this->assertEquals('Anthony', $result['values'][$contactID]['first_name']);
6a488035
TO
2017 }
2018
2019 /**
381fa321 2020 * Test civicrm_contact_getquick() with empty name param.
6a488035
TO
2021 */
2022 public function testContactGetQuick() {
ae8bd424 2023 $contactID = $this->individualCreate(['first_name' => 'Test', 'last_name' => 'Contact', 'email' => 'TestContact@example.com']);
6a488035 2024
ae8bd424 2025 $result = $this->callAPISuccess('contact', 'getquick', ['name' => 'T']);
2026 $this->assertEquals($contactID, $result['values'][0]['id']);
2027 $params = [
a9096cd1
SL
2028 'name' => "TestContact@example.com",
2029 'field_name' => 'sort_name',
ae8bd424 2030 ];
a9096cd1 2031 $result = $this->callAPISuccess('contact', 'getquick', $params);
ae8bd424 2032 $this->assertEquals($contactID, $result['values'][0]['id']);
6a488035
TO
2033 }
2034
2035 /**
fe482240 2036 * Test civicrm_contact_get) with empty params.
46312f7d 2037 *
2d932085 2038 * @param int $version
46312f7d 2039 *
2d932085 2040 * @dataProvider versionThreeAndFour
6a488035 2041 */
2d932085
CW
2042 public function testContactGetEmptyParams($version) {
2043 $this->_apiversion = $version;
ae8bd424 2044 $this->callAPISuccess('contact', 'get', []);
6a488035
TO
2045 }
2046
2047 /**
fe482240 2048 * Test civicrm_contact_get(,true) with no matches.
46312f7d 2049 *
2d932085 2050 * @param int $version
46312f7d 2051 *
2d932085 2052 * @dataProvider versionThreeAndFour
6a488035 2053 */
2d932085
CW
2054 public function testContactGetOldParamsNoMatches($version) {
2055 $this->_apiversion = $version;
ae8bd424 2056 $this->individualCreate();
2057 $result = $this->callAPISuccess('contact', 'get', ['first_name' => 'Fred']);
fe482240 2058 $this->assertEquals(0, $result['count']);
6a488035
TO
2059 }
2060
2061 /**
fe482240 2062 * Test civicrm_contact_get(,true) with one match.
6a488035
TO
2063 */
2064 public function testContactGetOldParamsOneMatch() {
ae8bd424 2065 $contactID = $this->individualCreate(['first_name' => 'Test', 'last_name' => 'Contact']);
6a488035 2066
ae8bd424 2067 $result = $this->callAPISuccess('contact', 'get', ['first_name' => 'Test']);
2068 $this->assertEquals($contactID, $result['values'][$contactID]['contact_id']);
2069 $this->assertEquals($contactID, $result['id']);
6a488035 2070 }
6a488035
TO
2071
2072 /**
fe482240 2073 * Test civicrm_contact_search_count().
6a488035
TO
2074 */
2075 public function testContactGetEmail() {
46312f7d 2076 $params = [
6a488035
TO
2077 'email' => 'man2@yahoo.com',
2078 'contact_type' => 'Individual',
2079 'location_type_id' => 1,
46312f7d 2080 ];
6a488035 2081
f6722559 2082 $contact = $this->callAPISuccess('contact', 'create', $params);
2083
46312f7d 2084 $params = [
6a488035 2085 'email' => 'man2@yahoo.com',
46312f7d 2086 ];
f6722559 2087 $result = $this->callAPIAndDocument('contact', 'get', $params, __FUNCTION__, __FILE__);
c8747697 2088 $this->assertEquals('man2@yahoo.com', $result['values'][$result['id']]['email']);
6a488035 2089
f6722559 2090 $this->callAPISuccess('contact', 'delete', $contact);
6a488035
TO
2091 }
2092
37f7ae88 2093 /**
2094 * Ensure consistent return format for option group fields.
46312f7d 2095 *
2d932085 2096 * @param int $version
46312f7d 2097 *
2d932085 2098 * @dataProvider versionThreeAndFour
37f7ae88 2099 */
2d932085
CW
2100 public function testSetPreferredCommunicationNull($version) {
2101 $this->_apiversion = $version;
46312f7d 2102 $contact = $this->callAPISuccess('contact', 'create', array_merge($this->_params, [
2103 'preferred_communication_method' => ['Phone', 'SMS'],
2104 ]));
2105 $preferredCommunicationMethod = $this->callAPISuccessGetValue('Contact', [
37f7ae88 2106 'id' => $contact['id'],
2107 'return' => 'preferred_communication_method',
46312f7d 2108 ]);
37f7ae88 2109 $this->assertNotEmpty($preferredCommunicationMethod);
46312f7d 2110 $contact = $this->callAPISuccess('contact', 'create', array_merge($this->_params, [
37f7ae88 2111 'preferred_communication_method' => 'null',
2112 'id' => $contact['id'],
46312f7d 2113 ]));
2114 $preferredCommunicationMethod = $this->callAPISuccessGetValue('Contact', [
37f7ae88 2115 'id' => $contact['id'],
2116 'return' => 'preferred_communication_method',
46312f7d 2117 ]);
37f7ae88 2118 $this->assertEmpty($preferredCommunicationMethod);
2119 }
2120
86ab13b7 2121 /**
2122 * Ensure consistent return format for option group fields.
936ededf 2123 *
2124 * @throws \CRM_Core_Exception
86ab13b7 2125 */
2126 public function testPseudoFields() {
46312f7d 2127 $params = [
2128 'preferred_communication_method' => ['Phone', 'SMS'],
86ab13b7 2129 'preferred_language' => 'en_US',
2130 'gender_id' => 'Female',
2131 'prefix_id' => 'Mrs.',
2132 'suffix_id' => 'II',
2133 'communication_style_id' => 'Formal',
46312f7d 2134 ];
86ab13b7 2135
2136 $contact = $this->callAPISuccess('contact', 'create', array_merge($this->_params, $params));
2137
46312f7d 2138 $result = $this->callAPISuccess('contact', 'getsingle', ['id' => $contact['id']]);
86ab13b7 2139 $this->assertEquals('Both', $result['preferred_mail_format']);
2140
2141 $this->assertEquals('en_US', $result['preferred_language']);
2142 $this->assertEquals(1, $result['communication_style_id']);
2143 $this->assertEquals(1, $result['gender_id']);
2144 $this->assertEquals('Female', $result['gender']);
2145 $this->assertEquals('Mrs.', $result['individual_prefix']);
2146 $this->assertEquals(1, $result['prefix_id']);
2147 $this->assertEquals('II', $result['individual_suffix']);
2148 $this->assertEquals(CRM_Core_PseudoConstant::getKey("CRM_Contact_BAO_Contact", 'suffix_id', 'II'), $result['suffix_id']);
2149 $this->callAPISuccess('contact', 'delete', $contact);
46312f7d 2150 $this->assertEquals([
86ab13b7 2151 CRM_Core_PseudoConstant::getKey("CRM_Contact_BAO_Contact", 'preferred_communication_method', 'Phone'),
2152 CRM_Core_PseudoConstant::getKey("CRM_Contact_BAO_Contact", 'preferred_communication_method', 'SMS'),
46312f7d 2153 ], $result['preferred_communication_method']);
86ab13b7 2154 }
2155
b1f09bea 2156 /**
fe482240
EM
2157 * Test birth date parameters.
2158 *
2159 * These include value, array & birth_date_high, birth_date_low
2160 * && deceased.
936ededf 2161 *
2162 * @throws \CRM_Core_Exception
b1f09bea 2163 */
4b58ed3b 2164 public function testContactGetBirthDate() {
46312f7d 2165 $contact1 = $this->callAPISuccess('contact', 'create', array_merge($this->_params, ['birth_date' => 'first day of next month - 2 years']));
2166 $contact2 = $this->callAPISuccess('contact', 'create', array_merge($this->_params, ['birth_date' => 'first day of next month - 5 years']));
2167 $contact3 = $this->callAPISuccess('contact', 'create', array_merge($this->_params, ['birth_date' => 'first day of next month -20 years']));
b1f09bea 2168
46312f7d 2169 $result = $this->callAPISuccess('contact', 'get', []);
b1f09bea 2170 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -2 years')), $result['values'][$contact1['id']]['birth_date']);
46312f7d 2171 $result = $this->callAPISuccess('contact', 'get', ['birth_date' => 'first day of next month -5 years']);
b1f09bea
E
2172 $this->assertEquals(1, $result['count']);
2173 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -5 years')), $result['values'][$contact2['id']]['birth_date']);
46312f7d 2174 $result = $this->callAPISuccess('contact', 'get', ['birth_date_high' => date('Y-m-d', strtotime('-6 years'))]);
b1f09bea
E
2175 $this->assertEquals(1, $result['count']);
2176 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -20 years')), $result['values'][$contact3['id']]['birth_date']);
46312f7d 2177 $result = $this->callAPISuccess('contact', 'get', [
92915c55
TO
2178 'birth_date_low' => date('Y-m-d', strtotime('-6 years')),
2179 'birth_date_high' => date('Y-m-d', strtotime('- 3 years')),
46312f7d 2180 ]);
b1f09bea
E
2181 $this->assertEquals(1, $result['count']);
2182 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -5 years')), $result['values'][$contact2['id']]['birth_date']);
46312f7d 2183 $result = $this->callAPISuccess('contact', 'get', [
92915c55
TO
2184 'birth_date_low' => '-6 years',
2185 'birth_date_high' => '- 3 years',
46312f7d 2186 ]);
9f60788a
EM
2187 $this->assertEquals(1, $result['count']);
2188 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -5 years')), $result['values'][$contact2['id']]['birth_date']);
b1f09bea
E
2189 }
2190
d0bfb983 2191 /**
2192 * Test Address parameters
2193 *
2194 * This include state_province, state_province_name, country
2195 */
2196 public function testContactGetWithAddressFields() {
46312f7d 2197 $individuals = [
2198 [
d0bfb983 2199 'first_name' => 'abc1',
2200 'contact_type' => 'Individual',
2201 'last_name' => 'xyz1',
46312f7d 2202 'api.address.create' => [
d0bfb983 2203 'country' => 'United States',
2204 'state_province_id' => 'Michigan',
2205 'location_type_id' => 1,
46312f7d 2206 ],
2207 ],
2208 [
d0bfb983 2209 'first_name' => 'abc2',
2210 'contact_type' => 'Individual',
2211 'last_name' => 'xyz2',
46312f7d 2212 'api.address.create' => [
d0bfb983 2213 'country' => 'United States',
2214 'state_province_id' => 'Alabama',
2215 'location_type_id' => 1,
46312f7d 2216 ],
2217 ],
2218 ];
d0bfb983 2219 foreach ($individuals as $params) {
2220 $contact = $this->callAPISuccess('contact', 'create', $params);
2221 }
2222
2223 // Check whether Contact get API return successfully with below Address params.
46312f7d 2224 $fieldsToTest = [
d0bfb983 2225 'state_province_name' => 'Michigan',
2226 'state_province' => 'Michigan',
2227 'country' => 'United States',
46312f7d 2228 'state_province_name' => ['IN' => ['Michigan', 'Alabama']],
2229 'state_province' => ['IN' => ['Michigan', 'Alabama']],
2230 ];
d0bfb983 2231 foreach ($fieldsToTest as $field => $value) {
46312f7d 2232 $getParams = [
d0bfb983 2233 'id' => $contact['id'],
2234 $field => $value,
46312f7d 2235 ];
41a74135 2236 $result = $this->callAPISuccess('Contact', 'get', $getParams);
2237 $this->assertEquals(1, $result['count']);
d0bfb983 2238 }
2239 }
2240
b1f09bea 2241 /**
fe482240
EM
2242 * Test Deceased date parameters.
2243 *
2244 * These include value, array & Deceased_date_high, Deceased date_low
d177a2a6 2245 * && deceased.
b1f09bea 2246 */
4b58ed3b 2247 public function testContactGetDeceasedDate() {
46312f7d 2248 $contact1 = $this->callAPISuccess('contact', 'create', array_merge($this->_params, ['deceased_date' => 'first day of next month - 2 years']));
2249 $contact2 = $this->callAPISuccess('contact', 'create', array_merge($this->_params, ['deceased_date' => 'first day of next month - 5 years']));
2250 $contact3 = $this->callAPISuccess('contact', 'create', array_merge($this->_params, ['deceased_date' => 'first day of next month -20 years']));
b1f09bea 2251
46312f7d 2252 $result = $this->callAPISuccess('contact', 'get', []);
b1f09bea 2253 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -2 years')), $result['values'][$contact1['id']]['deceased_date']);
46312f7d 2254 $result = $this->callAPISuccess('contact', 'get', ['deceased_date' => 'first day of next month -5 years']);
b1f09bea
E
2255 $this->assertEquals(1, $result['count']);
2256 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -5 years')), $result['values'][$contact2['id']]['deceased_date']);
46312f7d 2257 $result = $this->callAPISuccess('contact', 'get', ['deceased_date_high' => date('Y-m-d', strtotime('-6 years'))]);
b1f09bea
E
2258 $this->assertEquals(1, $result['count']);
2259 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -20 years')), $result['values'][$contact3['id']]['deceased_date']);
46312f7d 2260 $result = $this->callAPISuccess('contact', 'get', [
92915c55
TO
2261 'deceased_date_low' => '-6 years',
2262 'deceased_date_high' => date('Y-m-d', strtotime('- 3 years')),
46312f7d 2263 ]);
b1f09bea
E
2264 $this->assertEquals(1, $result['count']);
2265 $this->assertEquals(date('Y-m-d', strtotime('first day of next month -5 years')), $result['values'][$contact2['id']]['deceased_date']);
2266 }
2267
e635f9d4 2268 /**
fe482240 2269 * Test for Contact.get id=@user:username.
e635f9d4 2270 */
00be9182 2271 public function testContactGetByUsername() {
fe482240 2272 // Setup - create contact with a uf-match.
46312f7d 2273 $cid = $this->individualCreate([
e635f9d4
TO
2274 'contact_type' => 'Individual',
2275 'first_name' => 'testGetByUsername',
2276 'last_name' => 'testGetByUsername',
46312f7d 2277 ]);
e635f9d4 2278
46312f7d 2279 $ufMatchParams = [
e635f9d4
TO
2280 'domain_id' => CRM_Core_Config::domainID(),
2281 'uf_id' => 99,
2282 'uf_name' => 'the-email-matching-key-is-not-really-the-username',
2283 'contact_id' => $cid,
46312f7d 2284 ];
e635f9d4
TO
2285 $ufMatch = CRM_Core_BAO_UFMatch::create($ufMatchParams);
2286 $this->assertTrue(is_numeric($ufMatch->id));
2287
2288 // setup - mock the calls to CRM_Utils_System_*::getUfId
dcadbba4 2289 $mockFunction = $this->mockMethod;
46312f7d 2290 $userSystem = $this->$mockFunction('CRM_Utils_System_UnitTests', ['getUfId']);
e635f9d4
TO
2291 $userSystem->expects($this->once())
2292 ->method('getUfId')
2293 ->with($this->equalTo('exampleUser'))
2294 ->will($this->returnValue(99));
2295 CRM_Core_Config::singleton()->userSystem = $userSystem;
2296
2297 // perform a lookup
46312f7d 2298 $result = $this->callAPISuccess('Contact', 'get', [
e635f9d4 2299 'id' => '@user:exampleUser',
46312f7d 2300 ]);
e635f9d4 2301 $this->assertEquals('testGetByUsername', $result['values'][$cid]['first_name']);
8d475ce9
CW
2302
2303 // Check search of contacts with & without uf records
2304 $result = $this->callAPISuccess('Contact', 'get', ['uf_user' => 1]);
2305 $this->assertArrayHasKey($cid, $result['values']);
2306
2307 $result = $this->callAPISuccess('Contact', 'get', ['uf_user' => 0]);
2308 $this->assertArrayNotHasKey($cid, $result['values']);
e635f9d4
TO
2309 }
2310
265cc07d 2311 /**
eceb18cc 2312 * Test to check return works OK.
265cc07d 2313 */
00be9182 2314 public function testContactGetReturnValues() {
46312f7d 2315 $extraParams = [
701a69da 2316 'nick_name' => 'Bob',
2317 'phone' => '456',
2318 'email' => 'e@mail.com',
46312f7d 2319 ];
265cc07d 2320 $contactID = $this->individualCreate($extraParams);
2321 //actually it turns out the above doesn't create a phone
46312f7d 2322 $this->callAPISuccess('phone', 'create', ['contact_id' => $contactID, 'phone' => '456']);
2323 $result = $this->callAPISuccess('contact', 'getsingle', ['id' => $contactID]);
265cc07d 2324 foreach ($extraParams as $key => $value) {
2325 $this->assertEquals($result[$key], $value);
2326 }
2327 //now we check they are still returned with 'return' key
46312f7d 2328 $result = $this->callAPISuccess('contact', 'getsingle', [
92915c55
TO
2329 'id' => $contactID,
2330 'return' => array_keys($extraParams),
46312f7d 2331 ]);
265cc07d 2332 foreach ($extraParams as $key => $value) {
2333 $this->assertEquals($result[$key], $value);
2334 }
2335 }
2336
701a69da 2337 /**
2338 * Test creating multiple phones using chaining.
2339 *
2d932085 2340 * @param int $version
46312f7d 2341 *
2d932085 2342 * @dataProvider versionThreeAndFour
46312f7d 2343 * @throws \Exception
701a69da 2344 */
2d932085
CW
2345 public function testCRM13252MultipleChainedPhones($version) {
2346 $this->_apiversion = $version;
265cc07d 2347 $contactID = $this->householdCreate();
46312f7d 2348 $this->callAPISuccessGetCount('phone', ['contact_id' => $contactID], 0);
2349 $params = [
5896d037
TO
2350 'contact_id' => $contactID,
2351 'household_name' => 'Household 1',
2352 'contact_type' => 'Household',
46312f7d 2353 'api.phone.create' => [
2354 0 => [
265cc07d 2355 'phone' => '111-111-1111',
2356 'location_type_id' => 1,
2357 'phone_type_id' => 1,
46312f7d 2358 ],
2359 1 => [
265cc07d 2360 'phone' => '222-222-2222',
2361 'location_type_id' => 1,
2362 'phone_type_id' => 2,
46312f7d 2363 ],
2364 ],
2365 ];
4b58ed3b 2366 $this->callAPISuccess('contact', 'create', $params);
46312f7d 2367 $this->callAPISuccessGetCount('phone', ['contact_id' => $contactID], 2);
265cc07d 2368
2369 }
5896d037 2370
e635f9d4 2371 /**
fe482240 2372 * Test for Contact.get id=@user:username (with an invalid username).
e635f9d4 2373 */
00be9182 2374 public function testContactGetByUnknownUsername() {
e635f9d4 2375 // setup - mock the calls to CRM_Utils_System_*::getUfId
dcadbba4 2376 $mockFunction = $this->mockMethod;
46312f7d 2377 $userSystem = $this->$mockFunction('CRM_Utils_System_UnitTests', ['getUfId']);
e635f9d4
TO
2378 $userSystem->expects($this->once())
2379 ->method('getUfId')
2380 ->with($this->equalTo('exampleUser'))
2381 ->will($this->returnValue(NULL));
2382 CRM_Core_Config::singleton()->userSystem = $userSystem;
2383
2384 // perform a lookup
46312f7d 2385 $result = $this->callAPIFailure('Contact', 'get', [
e635f9d4 2386 'id' => '@user:exampleUser',
46312f7d 2387 ]);
e635f9d4
TO
2388 $this->assertRegExp('/cannot be resolved to a contact ID/', $result['error_message']);
2389 }
2390
6a488035 2391 /**
701a69da 2392 * Verify attempt to create individual with chained arrays and sequential.
46312f7d 2393 *
2d932085 2394 * @param int $version
46312f7d 2395 *
2d932085 2396 * @dataProvider versionThreeAndFour
48bb2598 2397 */
2d932085
CW
2398 public function testGetIndividualWithChainedArraysAndSequential($version) {
2399 $this->_apiversion = $version;
48bb2598
JV
2400 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
2401 $params['custom_' . $ids['custom_field_id']] = "custom string";
2402
84b51197 2403 $moreIDs = $this->CustomGroupMultipleCreateWithFields();
46312f7d 2404 $params = [
48bb2598
JV
2405 'sequential' => 1,
2406 'first_name' => 'abc3',
2407 'last_name' => 'xyz3',
2408 'contact_type' => 'Individual',
2409 'email' => 'man3@yahoo.com',
46312f7d 2410 'api.website.create' => [
2411 [
48bb2598 2412 'url' => "http://civicrm.org",
46312f7d 2413 ],
2414 [
48bb2598 2415 'url' => "https://civicrm.org",
46312f7d 2416 ],
2417 ],
2418 ];
48bb2598
JV
2419
2420 $result = $this->callAPISuccess('Contact', 'create', $params);
2421
48bb2598 2422 // delete the contact and custom groups
46312f7d 2423 $this->callAPISuccess('contact', 'delete', ['id' => $result['id']]);
48bb2598 2424 $this->customGroupDelete($ids['custom_group_id']);
84b51197 2425 $this->customGroupDelete($moreIDs['custom_group_id']);
48bb2598
JV
2426
2427 $this->assertEquals($result['id'], $result['values'][0]['id']);
2428 $this->assertArrayKeyExists('api.website.create', $result['values'][0]);
2429 }
2430
2431 /**
701a69da 2432 * Verify attempt to create individual with chained arrays.
6a488035 2433 */
00be9182 2434 public function testGetIndividualWithChainedArrays() {
6a488035
TO
2435 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
2436 $params['custom_' . $ids['custom_field_id']] = "custom string";
2437
381fa321 2438 $moreIDs = $this->CustomGroupMultipleCreateWithFields();
5c49fee0 2439 $description = "This demonstrates the usage of chained api functions.\nIn this case no notes or custom fields have been created.";
5896d037 2440 $subfile = "APIChainedArray";
46312f7d 2441 $params = [
6a488035
TO
2442 'first_name' => 'abc3',
2443 'last_name' => 'xyz3',
2444 'contact_type' => 'Individual',
2445 'email' => 'man3@yahoo.com',
46312f7d 2446 'api.contribution.create' => [
6a488035
TO
2447 'receive_date' => '2010-01-01',
2448 'total_amount' => 100.00,
2449 'financial_type_id' => 1,
2450 'payment_instrument_id' => 1,
2451 'non_deductible_amount' => 10.00,
2452 'fee_amount' => 50.00,
2453 'net_amount' => 90.00,
2454 'trxn_id' => 12345,
2455 'invoice_id' => 67890,
2456 'source' => 'SSF',
2457 'contribution_status_id' => 1,
46312f7d 2458 ],
2459 'api.contribution.create.1' => [
6a488035
TO
2460 'receive_date' => '2011-01-01',
2461 'total_amount' => 120.00,
6c6e6187 2462 'financial_type_id' => $this->_financialTypeId = 1,
6a488035
TO
2463 'payment_instrument_id' => 1,
2464 'non_deductible_amount' => 10.00,
2465 'fee_amount' => 50.00,
2466 'net_amount' => 90.00,
2467 'trxn_id' => 12335,
2468 'invoice_id' => 67830,
2469 'source' => 'SSF',
2470 'contribution_status_id' => 1,
46312f7d 2471 ],
2472 'api.website.create' => [
2473 [
6a488035 2474 'url' => "http://civicrm.org",
46312f7d 2475 ],
2476 ],
2477 ];
6a488035 2478
f6722559 2479 $result = $this->callAPISuccess('Contact', 'create', $params);
46312f7d 2480 $params = [
f6722559 2481 'id' => $result['id'],
46312f7d 2482 'api.website.get' => [],
2483 'api.Contribution.get' => [
6a488035 2484 'total_amount' => '120.00',
46312f7d 2485 ],
5896d037 2486 'api.CustomValue.get' => 1,
6a488035 2487 'api.Note.get' => 1,
46312f7d 2488 ];
f6722559 2489 $result = $this->callAPIAndDocument('Contact', 'Get', $params, __FUNCTION__, __FILE__, $description, $subfile);
6a488035 2490 // delete the contact
f6722559 2491 $this->callAPISuccess('contact', 'delete', $result);
6a488035 2492 $this->customGroupDelete($ids['custom_group_id']);
381fa321 2493 $this->customGroupDelete($moreIDs['custom_group_id']);
4b58ed3b
EM
2494 $this->assertEquals(0, $result['values'][$result['id']]['api.website.get']['is_error']);
2495 $this->assertEquals("http://civicrm.org", $result['values'][$result['id']]['api.website.get']['values'][0]['url']);
6a488035
TO
2496 }
2497
a77b0380 2498 /**
701a69da 2499 * Verify attempt to create individual with chained arrays and sequential.
a77b0380 2500 *
2d932085 2501 * @see https://issues.civicrm.org/jira/browse/CRM-15815
46312f7d 2502 *
2d932085 2503 * @param int $version
46312f7d 2504 *
2d932085 2505 * @dataProvider versionThreeAndFour
a77b0380 2506 */
2d932085
CW
2507 public function testCreateIndividualWithChainedArrayAndSequential($version) {
2508 $this->_apiversion = $version;
46312f7d 2509 $params = [
a77b0380
JV
2510 'sequential' => 1,
2511 'first_name' => 'abc5',
2512 'last_name' => 'xyz5',
2513 'contact_type' => 'Individual',
2514 'email' => 'woman5@yahoo.com',
46312f7d 2515 'api.phone.create' => [
2516 ['phone' => '03-231 07 95'],
2517 ['phone' => '03-232 51 62'],
2518 ],
2519 'api.website.create' => [
a77b0380 2520 'url' => 'http://civicrm.org',
46312f7d 2521 ],
2522 ];
a77b0380
JV
2523 $result = $this->callAPISuccess('Contact', 'create', $params);
2524
2525 // I could try to parse the result to see whether the two phone numbers
2526 // and the website are there, but I am not sure about the correct format.
2527 // So I will just fetch it again before checking.
2528 // See also http://forum.civicrm.org/index.php/topic,35393.0.html
46312f7d 2529 $params = [
a77b0380
JV
2530 'sequential' => 1,
2531 'id' => $result['id'],
46312f7d 2532 'api.website.get' => [],
2533 'api.phone.get' => [],
2534 ];
a77b0380
JV
2535 $result = $this->callAPISuccess('Contact', 'get', $params);
2536
2537 // delete the contact
2538 $this->callAPISuccess('contact', 'delete', $result);
2539
2540 $this->assertEquals(2, $result['values'][0]['api.phone.get']['count']);
2541 $this->assertEquals(1, $result['values'][0]['api.website.get']['count']);
2542 }
2543
701a69da 2544 /**
2545 * Test retrieving an individual with chained array syntax.
2546 */
00be9182 2547 public function testGetIndividualWithChainedArraysFormats() {
5c49fee0 2548 $description = "This demonstrates the usage of chained api functions.\nIn this case no notes or custom fields have been created.";
6a488035
TO
2549 $subfile = "APIChainedArrayFormats";
2550 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
2551 $params['custom_' . $ids['custom_field_id']] = "custom string";
2552
381fa321 2553 $moreIDs = $this->CustomGroupMultipleCreateWithFields();
46312f7d 2554 $params = [
6a488035
TO
2555 'first_name' => 'abc3',
2556 'last_name' => 'xyz3',
2557 'contact_type' => 'Individual',
2558 'email' => 'man3@yahoo.com',
46312f7d 2559 'api.contribution.create' => [
6a488035
TO
2560 'receive_date' => '2010-01-01',
2561 'total_amount' => 100.00,
f6722559 2562 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
2563 'payment_instrument_id' => 1,
2564 'non_deductible_amount' => 10.00,
2565 'fee_amount' => 50.00,
2566 'net_amount' => 90.00,
2567 'source' => 'SSF',
2568 'contribution_status_id' => 1,
25ac4ffa 2569 'skipCleanMoney' => 1,
46312f7d 2570 ],
2571 'api.contribution.create.1' => [
6a488035
TO
2572 'receive_date' => '2011-01-01',
2573 'total_amount' => 120.00,
f6722559 2574 'financial_type_id' => $this->_financialTypeId,
6a488035
TO
2575 'payment_instrument_id' => 1,
2576 'non_deductible_amount' => 10.00,
2577 'fee_amount' => 50.00,
2578 'net_amount' => 90.00,
2579 'source' => 'SSF',
2580 'contribution_status_id' => 1,
25ac4ffa 2581 'skipCleanMoney' => 1,
46312f7d 2582 ],
2583 'api.website.create' => [
2584 [
6a488035 2585 'url' => "http://civicrm.org",
46312f7d 2586 ],
2587 ],
2588 ];
6a488035 2589
f6722559 2590 $result = $this->callAPISuccess('Contact', 'create', $params);
46312f7d 2591 $params = [
f6722559 2592 'id' => $result['id'],
46312f7d 2593 'api.website.getValue' => ['return' => 'url'],
2594 'api.Contribution.getCount' => [],
6a488035
TO
2595 'api.CustomValue.get' => 1,
2596 'api.Note.get' => 1,
46312f7d 2597 'api.Membership.getCount' => [],
2598 ];
f6722559 2599 $result = $this->callAPIAndDocument('Contact', 'Get', $params, __FUNCTION__, __FILE__, $description, $subfile);
4b58ed3b
EM
2600 $this->assertEquals(2, $result['values'][$result['id']]['api.Contribution.getCount']);
2601 $this->assertEquals(0, $result['values'][$result['id']]['api.Note.get']['is_error']);
2602 $this->assertEquals("http://civicrm.org", $result['values'][$result['id']]['api.website.getValue']);
6a488035 2603
f6722559 2604 $this->callAPISuccess('contact', 'delete', $result);
6a488035 2605 $this->customGroupDelete($ids['custom_group_id']);
381fa321 2606 $this->customGroupDelete($moreIDs['custom_group_id']);
6a488035
TO
2607 }
2608
381fa321 2609 /**
2610 * Test complex chaining.
2611 */
00be9182 2612 public function testGetIndividualWithChainedArraysAndMultipleCustom() {
6a488035
TO
2613 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
2614 $params['custom_' . $ids['custom_field_id']] = "custom string";
381fa321 2615 $moreIDs = $this->CustomGroupMultipleCreateWithFields();
46312f7d 2616 $andMoreIDs = $this->CustomGroupMultipleCreateWithFields([
92915c55
TO
2617 'title' => "another group",
2618 'name' => 'another name',
46312f7d 2619 ]);
5c49fee0 2620 $description = "This demonstrates the usage of chained api functions with multiple custom fields.";
6a488035 2621 $subfile = "APIChainedArrayMultipleCustom";
46312f7d 2622 $params = [
6a488035
TO
2623 'first_name' => 'abc3',
2624 'last_name' => 'xyz3',
2625 'contact_type' => 'Individual',
2626 'email' => 'man3@yahoo.com',
46312f7d 2627 'api.contribution.create' => [
6a488035
TO
2628 'receive_date' => '2010-01-01',
2629 'total_amount' => 100.00,
5896d037 2630 'financial_type_id' => 1,
6a488035
TO
2631 'payment_instrument_id' => 1,
2632 'non_deductible_amount' => 10.00,
2633 'fee_amount' => 50.00,
2634 'net_amount' => 90.00,
2635 'trxn_id' => 12345,
2636 'invoice_id' => 67890,
2637 'source' => 'SSF',
2638 'contribution_status_id' => 1,
25ac4ffa 2639 'skipCleanMoney' => 1,
46312f7d 2640 ],
2641 'api.contribution.create.1' => [
6a488035
TO
2642 'receive_date' => '2011-01-01',
2643 'total_amount' => 120.00,
5896d037 2644 'financial_type_id' => 1,
6a488035
TO
2645 'payment_instrument_id' => 1,
2646 'non_deductible_amount' => 10.00,
2647 'fee_amount' => 50.00,
2648 'net_amount' => 90.00,
2649 'trxn_id' => 12335,
2650 'invoice_id' => 67830,
2651 'source' => 'SSF',
2652 'contribution_status_id' => 1,
25ac4ffa 2653 'skipCleanMoney' => 1,
46312f7d 2654 ],
2655 'api.website.create' => [
2656 [
6a488035 2657 'url' => "http://civicrm.org",
46312f7d 2658 ],
2659 ],
6a488035 2660 'custom_' . $ids['custom_field_id'] => "value 1",
381fa321 2661 'custom_' . $moreIDs['custom_field_id'][0] => "value 2",
2662 'custom_' . $moreIDs['custom_field_id'][1] => "warm beer",
2663 'custom_' . $andMoreIDs['custom_field_id'][1] => "vegemite",
46312f7d 2664 ];
6a488035 2665
f6722559 2666 $result = $this->callAPISuccess('Contact', 'create', $params);
46312f7d 2667 $result = $this->callAPISuccess('Contact', 'create', [
6c6e6187 2668 'contact_type' => 'Individual',
5896d037
TO
2669 'id' => $result['id'],
2670 'custom_' .
381fa321 2671 $moreIDs['custom_field_id'][0] => "value 3",
5896d037
TO
2672 'custom_' .
2673 $ids['custom_field_id'] => "value 4",
46312f7d 2674 ]);
6a488035 2675
46312f7d 2676 $params = [
f6722559 2677 'id' => $result['id'],
46312f7d 2678 'api.website.getValue' => ['return' => 'url'],
2679 'api.Contribution.getCount' => [],
6a488035 2680 'api.CustomValue.get' => 1,
46312f7d 2681 ];
f6722559 2682 $result = $this->callAPIAndDocument('Contact', 'Get', $params, __FUNCTION__, __FILE__, $description, $subfile);
2683
6a488035 2684 $this->customGroupDelete($ids['custom_group_id']);
381fa321 2685 $this->customGroupDelete($moreIDs['custom_group_id']);
2686 $this->customGroupDelete($andMoreIDs['custom_group_id']);
4b58ed3b
EM
2687 $this->assertEquals(0, $result['values'][$result['id']]['api.CustomValue.get']['is_error']);
2688 $this->assertEquals('http://civicrm.org', $result['values'][$result['id']]['api.website.getValue']);
6a488035 2689 }
5896d037 2690
d424ffde 2691 /**
381fa321 2692 * Test checks usage of $values to pick & choose inputs.
2d932085
CW
2693 *
2694 * Api3 Only - chaining syntax is too funky for v4 (assuming entityTag "entity_id" field will be filled by magic)
6a488035 2695 */
00be9182 2696 public function testChainingValuesCreate() {
5c49fee0
CW
2697 $description = "This demonstrates the usage of chained api functions. Specifically it has one 'parent function' &
2698 2 child functions - one receives values from the parent (Contact) and the other child (Tag).";
6a488035 2699 $subfile = "APIChainedArrayValuesFromSiblingFunction";
46312f7d 2700 $params = [
6c6e6187 2701 'display_name' => 'batman',
5896d037 2702 'contact_type' => 'Individual',
46312f7d 2703 'api.tag.create' => [
701a69da 2704 'name' => '$value.id',
2705 'description' => '$value.display_name',
2706 'format.only_id' => 1,
46312f7d 2707 ],
2708 'api.entity_tag.create' => ['tag_id' => '$value.api.tag.create'],
2709 ];
f6722559 2710 $result = $this->callAPIAndDocument('Contact', 'Create', $params, __FUNCTION__, __FILE__, $description, $subfile);
6a488035 2711 $this->assertEquals(0, $result['values'][$result['id']]['api.entity_tag.create']['is_error']);
f6722559 2712
46312f7d 2713 $tablesToTruncate = [
6a488035
TO
2714 'civicrm_contact',
2715 'civicrm_activity',
2716 'civicrm_entity_tag',
2717 'civicrm_tag',
46312f7d 2718 ];
6a488035
TO
2719 $this->quickCleanup($tablesToTruncate, TRUE);
2720 }
2721
d424ffde 2722 /**
fe482240 2723 * Test TrueFalse format - I couldn't come up with an easy way to get an error on Get.
46312f7d 2724 *
2d932085 2725 * @param int $version
46312f7d 2726 *
2d932085 2727 * @dataProvider versionThreeAndFour
6a488035 2728 */
2d932085
CW
2729 public function testContactGetFormatIsSuccessTrue($version) {
2730 $this->_apiversion = $version;
ae8bd424 2731 $contactID = $this->individualCreate(['first_name' => 'Test', 'last_name' => 'Contact']);
6a488035
TO
2732 $description = "This demonstrates use of the 'format.is_success' param.
2733 This param causes only the success or otherwise of the function to be returned as BOOLEAN";
2734 $subfile = "FormatIsSuccess_True";
ae8bd424 2735 $params = ['id' => $contactID, 'format.is_success' => 1];
5896d037 2736 $result = $this->callAPIAndDocument('Contact', 'Get', $params, __FUNCTION__, __FILE__, $description, $subfile);
6a488035 2737 $this->assertEquals(1, $result);
f6722559 2738 $this->callAPISuccess('Contact', 'Delete', $params);
6a488035 2739 }
5896d037 2740
d424ffde 2741 /**
fe482240 2742 * Test TrueFalse format.
46312f7d 2743 *
2d932085 2744 * @param int $version
46312f7d 2745 *
2d932085 2746 * @dataProvider versionThreeAndFour
6a488035 2747 */
2d932085
CW
2748 public function testContactCreateFormatIsSuccessFalse($version) {
2749 $this->_apiversion = $version;
6a488035
TO
2750
2751 $description = "This demonstrates use of the 'format.is_success' param.
2752 This param causes only the success or otherwise of the function to be returned as BOOLEAN";
2753 $subfile = "FormatIsSuccess_Fail";
46312f7d 2754 $params = ['id' => 500, 'format.is_success' => 1];
5896d037 2755 $result = $this->callAPIAndDocument('Contact', 'Create', $params, __FUNCTION__, __FILE__, $description, $subfile);
6a488035
TO
2756 $this->assertEquals(0, $result);
2757 }
5896d037 2758
3628dc86 2759 /**
2760 * Test long display names.
2761 *
2762 * CRM-21258
46312f7d 2763 *
2d932085 2764 * @param int $version
46312f7d 2765 *
2d932085 2766 * @dataProvider versionThreeAndFour
3628dc86 2767 */
2d932085
CW
2768 public function testContactCreateLongDisplayName($version) {
2769 $this->_apiversion = $version;
46312f7d 2770 $result = $this->callAPISuccess('Contact', 'Create', [
3628dc86 2771 'first_name' => str_pad('a', 64, 'a'),
2772 'last_name' => str_pad('a', 64, 'a'),
2773 'contact_type' => 'Individual',
46312f7d 2774 ]);
3628dc86 2775 $this->assertEquals('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', $result['values'][$result['id']]['display_name']);
2776 $this->assertEquals('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', $result['values'][$result['id']]['sort_name']);
2777 }
2778
1bdbd4ec 2779 /**
2780 * Test that we can set the sort name via the api or alter it via a hook.
2781 *
2782 * As of writing this is being fixed for Organization & Household but it makes sense to do for individuals too.
46312f7d 2783 *
2d932085 2784 * @param int $version
46312f7d 2785 *
2d932085 2786 * @dataProvider versionThreeAndFour
1bdbd4ec 2787 */
2d932085
CW
2788 public function testCreateAlterSortName($version) {
2789 $this->_apiversion = $version;
1bdbd4ec 2790 $organizationID = $this->organizationCreate(['organization_name' => 'The Justice League', 'sort_name' => 'Justice League, The']);
2791 $organization = $this->callAPISuccessGetSingle('Contact', ['return' => ['sort_name', 'display_name'], 'id' => $organizationID]);
2792 $this->assertEquals('Justice League, The', $organization['sort_name']);
2793 $this->assertEquals('The Justice League', $organization['display_name']);
46312f7d 2794 $this->hookClass->setHook('civicrm_pre', [$this, 'killTheJusticeLeague']);
1bdbd4ec 2795 $this->organizationCreate(['id' => $organizationID, 'sort_name' => 'Justice League, The']);
2796 $organization = $this->callAPISuccessGetSingle('Contact', ['return' => ['sort_name', 'display_name', 'is_deceased'], 'id' => $organizationID]);
2797 $this->assertEquals('Steppenwolf wuz here', $organization['display_name']);
2798 $this->assertEquals('Steppenwolf wuz here', $organization['sort_name']);
2799 $this->assertEquals(1, $organization['is_deceased']);
2800
2801 $householdID = $this->householdCreate();
2802 $household = $this->callAPISuccessGetSingle('Contact', ['return' => ['sort_name', 'display_name'], 'id' => $householdID]);
2803 $this->assertEquals('Steppenwolf wuz here', $household['display_name']);
2804 $this->assertEquals('Steppenwolf wuz here', $household['sort_name']);
2805 }
2806
2807 /**
2808 * Implements hook_pre().
2809 */
2810 public function killTheJusticeLeague($op, $entity, $id, &$params) {
2811 $params['sort_name'] = 'Steppenwolf wuz here';
2812 $params['display_name'] = 'Steppenwolf wuz here';
2813 $params['is_deceased'] = 1;
2814 }
2815
d424ffde 2816 /**
fe482240 2817 * Test Single Entity format.
46312f7d 2818 *
2d932085 2819 * @param int $version
46312f7d 2820 *
2d932085 2821 * @dataProvider versionThreeAndFour
6a488035 2822 */
2d932085
CW
2823 public function testContactGetSingleEntityArray($version) {
2824 $this->_apiversion = $version;
ae8bd424 2825 $contactID = $this->individualCreate(['first_name' => 'Test', 'last_name' => 'Contact']);
6a488035 2826 $description = "This demonstrates use of the 'format.single_entity_array' param.
5c49fee0
CW
2827 This param causes the only contact to be returned as an array without the other levels.
2828 It will be ignored if there is not exactly 1 result";
6a488035 2829 $subfile = "GetSingleContact";
ae8bd424 2830 $result = $this->callAPIAndDocument('Contact', 'GetSingle', ['id' => $contactID], __FUNCTION__, __FILE__, $description, $subfile);
2831 $this->assertEquals('Mr. Test Contact II', $result['display_name']);
2832 $this->callAPISuccess('Contact', 'Delete', ['id' => $contactID]);
6a488035
TO
2833 }
2834
d424ffde 2835 /**
381fa321 2836 * Test Single Entity format.
46312f7d 2837 *
2d932085 2838 * @param int $version
46312f7d 2839 *
2d932085 2840 * @dataProvider versionThreeAndFour
6a488035 2841 */
2d932085
CW
2842 public function testContactGetFormatCountOnly($version) {
2843 $this->_apiversion = $version;
ae8bd424 2844 $contactID = $this->individualCreate(['first_name' => 'Test', 'last_name' => 'Contact']);
5c49fee0
CW
2845 $description = "This demonstrates use of the 'getCount' action.
2846 This param causes the count of the only function to be returned as an integer.";
ae8bd424 2847 $params = ['id' => $contactID];
381fa321 2848 $result = $this->callAPIAndDocument('Contact', 'GetCount', $params, __FUNCTION__, __FILE__, $description,
84b51197 2849 'GetCountContact');
4b58ed3b 2850 $this->assertEquals('1', $result);
f6722559 2851 $this->callAPISuccess('Contact', 'Delete', $params);
6a488035 2852 }
5896d037 2853
d424ffde 2854 /**
381fa321 2855 * Test id only format.
46312f7d 2856 *
2d932085 2857 * @param int $version
46312f7d 2858 *
2d932085 2859 * @dataProvider versionThreeAndFour
408b79bf 2860 */
2d932085
CW
2861 public function testContactGetFormatIDOnly($version) {
2862 $this->_apiversion = $version;
ae8bd424 2863 $contactID = $this->individualCreate(['first_name' => 'Test', 'last_name' => 'Contact']);
5c49fee0
CW
2864 $description = "This demonstrates use of the 'format.id_only' param.
2865 This param causes the id of the only entity to be returned as an integer.
2866 It will be ignored if there is not exactly 1 result";
6a488035 2867 $subfile = "FormatOnlyID";
ae8bd424 2868 $params = ['id' => $contactID, 'format.only_id' => 1];
5896d037 2869 $result = $this->callAPIAndDocument('Contact', 'Get', $params, __FUNCTION__, __FILE__, $description, $subfile);
ae8bd424 2870 $this->assertEquals($contactID, $result);
f6722559 2871 $this->callAPISuccess('Contact', 'Delete', $params);
6a488035
TO
2872 }
2873
d424ffde 2874 /**
381fa321 2875 * Test id only format.
46312f7d 2876 *
2d932085 2877 * @param int $version
46312f7d 2878 *
2d932085 2879 * @dataProvider versionThreeAndFour
408b79bf 2880 */
2d932085
CW
2881 public function testContactGetFormatSingleValue($version) {
2882 $this->_apiversion = $version;
ae8bd424 2883 $contactID = $this->individualCreate(['first_name' => 'Test', 'last_name' => 'Contact']);
6a488035 2884 $description = "This demonstrates use of the 'format.single_value' param.
5c49fee0
CW
2885 This param causes only a single value of the only entity to be returned as an string.
2886 It will be ignored if there is not exactly 1 result";
4b58ed3b 2887 $subFile = "FormatSingleValue";
ae8bd424 2888 $params = ['id' => $contactID, 'return' => 'display_name'];
a828d7b8 2889 $result = $this->callAPIAndDocument('Contact', 'getvalue', $params, __FUNCTION__, __FILE__, $description, $subFile);
ae8bd424 2890 $this->assertEquals('Mr. Test Contact II', $result);
f6722559 2891 $this->callAPISuccess('Contact', 'Delete', $params);
6a488035
TO
2892 }
2893
b2130237 2894 /**
381fa321 2895 * Test that permissions are respected when creating contacts.
46312f7d 2896 *
2d932085 2897 * @param int $version
46312f7d 2898 *
2d932085 2899 * @dataProvider versionThreeAndFour
b2130237 2900 */
2d932085
CW
2901 public function testContactCreationPermissions($version) {
2902 $this->_apiversion = $version;
46312f7d 2903 $params = [
6c6e6187 2904 'contact_type' => 'Individual',
5896d037 2905 'first_name' => 'Foo',
6a488035
TO
2906 'last_name' => 'Bear',
2907 'check_permissions' => TRUE,
46312f7d 2908 ];
6a488035 2909 $config = CRM_Core_Config::singleton();
46312f7d 2910 $config->userPermissionClass->permissions = ['access CiviCRM'];
d0e1eff2 2911 $result = $this->callAPIFailure('contact', 'create', $params);
2d932085 2912 $this->assertContains('failed', $result['error_message'], 'lacking permissions should not be enough to create a contact');
6a488035 2913
46312f7d 2914 $config->userPermissionClass->permissions = ['access CiviCRM', 'add contacts', 'import contacts'];
701a69da 2915 $this->callAPISuccess('contact', 'create', $params);
6a488035
TO
2916 }
2917
fa6448fa
EM
2918 /**
2919 * Test that delete with skip undelete respects permissions.
2d932085 2920 * TODO: Api4
fa6448fa
EM
2921 */
2922 public function testContactDeletePermissions() {
2923 $contactID = $this->individualCreate();
46312f7d 2924 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM'];
2925 $this->callAPIFailure('Contact', 'delete', [
fa6448fa
EM
2926 'id' => $contactID,
2927 'check_permissions' => 1,
2928 'skip_undelete' => 1,
46312f7d 2929 ]);
2930 $this->callAPISuccess('Contact', 'delete', [
fa6448fa
EM
2931 'id' => $contactID,
2932 'check_permissions' => 0,
2933 'skip_undelete' => 1,
46312f7d 2934 ]);
fa6448fa
EM
2935 }
2936
381fa321 2937 /**
2938 * Test update with check permissions set.
46312f7d 2939 *
2d932085 2940 * @param int $version
46312f7d 2941 *
2d932085 2942 * @dataProvider versionThreeAndFour
381fa321 2943 */
2d932085
CW
2944 public function testContactUpdatePermissions($version) {
2945 $this->_apiversion = $version;
46312f7d 2946 $params = [
5896d037
TO
2947 'contact_type' => 'Individual',
2948 'first_name' => 'Foo',
2949 'last_name' => 'Bear',
21dfd5f5 2950 'check_permissions' => TRUE,
46312f7d 2951 ];
f6722559 2952 $result = $this->callAPISuccess('contact', 'create', $params);
6a488035 2953 $config = CRM_Core_Config::singleton();
46312f7d 2954 $params = [
5896d037
TO
2955 'id' => $result['id'],
2956 'contact_type' => 'Individual',
2957 'last_name' => 'Bar',
21dfd5f5 2958 'check_permissions' => TRUE,
46312f7d 2959 ];
6a488035 2960
46312f7d 2961 $config->userPermissionClass->permissions = ['access CiviCRM'];
d0e1eff2 2962 $result = $this->callAPIFailure('contact', 'update', $params);
0a61b6e2 2963 $this->assertEquals('Permission denied to modify contact record', $result['error_message']);
6a488035 2964
46312f7d 2965 $config->userPermissionClass->permissions = [
5896d037
TO
2966 'access CiviCRM',
2967 'add contacts',
2968 'view all contacts',
2969 'edit all contacts',
21dfd5f5 2970 'import contacts',
46312f7d 2971 ];
701a69da 2972 $this->callAPISuccess('contact', 'update', $params);
6a488035
TO
2973 }
2974
381fa321 2975 /**
2976 * Test contact proximity api.
2977 */
00be9182 2978 public function testContactProximity() {
6a488035
TO
2979 // first create a contact with a SF location with a specific
2980 // geocode
2981 $contactID = $this->organizationCreate();
2982
2983 // now create the address
46312f7d 2984 $params = [
6a488035
TO
2985 'street_address' => '123 Main Street',
2986 'city' => 'San Francisco',
2987 'is_primary' => 1,
2988 'country_id' => 1228,
2989 'state_province_id' => 1004,
2990 'geo_code_1' => '37.79',
2991 'geo_code_2' => '-122.40',
2992 'location_type_id' => 1,
2993 'contact_id' => $contactID,
46312f7d 2994 ];
6a488035 2995
f6722559 2996 $result = $this->callAPISuccess('address', 'create', $params);
ba4a1892 2997 $this->assertEquals(1, $result['count']);
6a488035
TO
2998
2999 // now do a proximity search with a close enough geocode and hope to match
3000 // that specific contact only!
46312f7d 3001 $proxParams = [
6a488035
TO
3002 'latitude' => 37.7,
3003 'longitude' => -122.3,
3004 'unit' => 'mile',
3005 'distance' => 10,
46312f7d 3006 ];
f6722559 3007 $result = $this->callAPISuccess('contact', 'proximity', $proxParams);
ba4a1892 3008 $this->assertEquals(1, $result['count']);
6a488035 3009 }
60ec9f43
E
3010
3011 /**
381fa321 3012 * Test that Ajax API permission is sufficient to access getquick api.
3013 *
1d6020f1 3014 * (note that getquick api is required for autocomplete & has ACL permissions applied)
60ec9f43 3015 */
fe482240 3016 public function testGetquickPermissionCRM13744() {
46312f7d 3017 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviEvent'];
3018 $this->callAPIFailure('contact', 'getquick', ['name' => 'b', 'check_permissions' => TRUE]);
3019 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM'];
3020 $this->callAPISuccess('contact', 'getquick', ['name' => 'b', 'check_permissions' => TRUE]);
3021 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access AJAX API'];
3022 $this->callAPISuccess('contact', 'getquick', ['name' => 'b', 'check_permissions' => TRUE]);
60ec9f43 3023 }
9c8096cb 3024
08f4ab8d 3025 /**
3026 * Test that getquick returns contacts with an exact first name match first.
2baa1e00 3027 *
3028 * The search string 'b' & 'bob' both return ordered by sort_name if includeOrderByClause
3029 * is true (default) but if it is false then matches are returned in ID order.
613643e0 3030 *
3031 * @dataProvider getSearchSortOptions
08f4ab8d 3032 */
613643e0 3033 public function testGetQuickExactFirst($searchParameters, $settings, $firstContact, $secondContact = NULL) {
08f4ab8d 3034 $this->getQuickSearchSampleData();
613643e0 3035 $this->callAPISuccess('Setting', 'create', $settings);
3036 $result = $this->callAPISuccess('contact', 'getquick', $searchParameters);
3037 $this->assertEquals($firstContact, $result['values'][0]['sort_name']);
3038 $this->assertEquals($secondContact, $result['values'][1]['sort_name']);
46312f7d 3039 $this->callAPISuccess('Setting', 'create', ['includeWildCardInName' => TRUE, 'includeOrderByClause' => TRUE]);
613643e0 3040 }
3041
3042 public function getSearchSortOptions() {
3043 $firstAlphabeticalContactBySortName = 'A Bobby, Bobby';
3044 $secondAlphabeticalContactBySortName = 'Aadvark, Bob';
3045 $secondAlphabeticalContactWithEmailBySortName = 'Bob, Bob';
3046 $firstAlphabeticalContactFirstNameBob = 'Aadvark, Bob';
46312f7d 3047 $secondAlphabeticalContactFirstNameBob = 'Bob, Bob';
613643e0 3048 $firstByIDContactFirstNameBob = 'Bob, Bob';
46312f7d 3049 $secondByIDContactFirstNameBob = 'K Bobby, Bob';
613643e0 3050 $firstContactByID = 'Bob, Bob';
3051 $secondContactByID = 'E Bobby, Bobby';
3052 $bobLikeEmail = 'A Bobby, Bobby';
3053
46312f7d 3054 return [
3055 'empty_search_basic' => [
3056 'search_parameters' => ['name' => '%'],
3057 'settings' => ['includeWildCardInName' => TRUE, 'includeOrderByClause' => TRUE],
613643e0 3058 'first_contact' => $firstAlphabeticalContactBySortName,
3059 'second_contact' => $secondAlphabeticalContactBySortName,
46312f7d 3060 ],
3061 'empty_search_basic_no_wildcard' => [
3062 'search_parameters' => ['name' => '%'],
3063 'settings' => ['includeWildCardInName' => FALSE, 'includeOrderByClause' => TRUE],
613643e0 3064 'first_contact' => $firstAlphabeticalContactBySortName,
3065 'second_contact' => $secondAlphabeticalContactBySortName,
46312f7d 3066 ],
3067 'single_letter_search_basic' => [
3068 'search_parameters' => ['name' => 'b'],
3069 'settings' => ['includeWildCardInName' => TRUE, 'includeOrderByClause' => TRUE],
613643e0 3070 'first_contact' => $firstAlphabeticalContactBySortName,
3071 'second_contact' => $secondAlphabeticalContactBySortName,
46312f7d 3072 ],
3073 'bob_search_basic' => [
3074 'search_parameters' => ['name' => 'bob'],
3075 'settings' => ['includeWildCardInName' => TRUE, 'includeOrderByClause' => TRUE],
613643e0 3076 'first_contact' => $firstAlphabeticalContactBySortName,
3077 'second_contact' => $secondAlphabeticalContactBySortName,
46312f7d 3078 ],
fae75b58
SL
3079 // This test has been disabled as is proving to be problematic to reproduce due to MySQL sorting issues between different versions
3080 // 'bob_search_no_orderby' => array(
3081 // 'search_parameters' => array('name' => 'bob'),
3082 // 'settings' => array('includeWildCardInName' => TRUE, 'includeOrderByClause' => FALSE),
3083 // 'first_contact' => $firstContactByID,
3084 // 'second_contact' => $secondContactByID,
3085 //),
46312f7d 3086 'bob_search_no_wildcard' => [
3087 'search_parameters' => ['name' => 'bob'],
3088 'settings' => ['includeWildCardInName' => FALSE, 'includeOrderByClause' => TRUE],
613643e0 3089 'second_contact' => $bobLikeEmail,
3090 'first_contact' => $secondAlphabeticalContactFirstNameBob,
46312f7d 3091 ],
613643e0 3092 // This should be the same as just no wildcard as if we had an exactMatch while searching by
3093 // sort name it would rise to the top CRM-19547
46312f7d 3094 'bob_search_no_wildcard_no_orderby' => [
3095 'search_parameters' => ['name' => 'bob'],
3096 'settings' => ['includeWildCardInName' => FALSE, 'includeOrderByClause' => TRUE],
613643e0 3097 'second_contact' => $bobLikeEmail,
3098 'first_contact' => $secondAlphabeticalContactFirstNameBob,
46312f7d 3099 ],
3100 'first_name_search_basic' => [
3101 'search_parameters' => ['name' => 'bob', 'field_name' => 'first_name'],
3102 'settings' => ['includeWildCardInName' => TRUE, 'includeOrderByClause' => TRUE],
613643e0 3103 'first_contact' => $firstAlphabeticalContactFirstNameBob,
3104 'second_contact' => $secondAlphabeticalContactFirstNameBob,
46312f7d 3105 ],
3106 'first_name_search_no_wildcard' => [
3107 'search_parameters' => ['name' => 'bob', 'field_name' => 'first_name'],
3108 'settings' => ['includeWildCardInName' => FALSE, 'includeOrderByClause' => TRUE],
613643e0 3109 'first_contact' => $firstAlphabeticalContactFirstNameBob,
3110 'second_contact' => $secondAlphabeticalContactFirstNameBob,
46312f7d 3111 ],
fae75b58
SL
3112 // This test has been disabled as is proving to be problematic to reproduce due to MySQL sorting issues between different versions
3113 //'first_name_search_no_orderby' => array(
3114 // 'search_parameters' => array('name' => 'bob', 'field_name' => 'first_name'),
3115 // 'settings' => array('includeWildCardInName' => TRUE, 'includeOrderByClause' => FALSE),
3116 // 'first_contact' => $firstByIDContactFirstNameBob,
3117 // 'second_contact' => $secondByIDContactFirstNameBob,
3118 //),
46312f7d 3119 'email_search_basic' => [
3120 'search_parameters' => ['name' => 'bob', 'field_name' => 'email', 'table_name' => 'eml'],
3121 'settings' => ['includeWildCardInName' => FALSE, 'includeOrderByClause' => TRUE],
613643e0 3122 'first_contact' => $firstAlphabeticalContactBySortName,
3123 'second_contact' => $secondAlphabeticalContactWithEmailBySortName,
46312f7d 3124 ],
3125 ];
2baa1e00 3126 }
3127
e9e27a80 3128 /**
3129 * Test that getquick returns contacts with an exact first name match first.
3130 */
3131 public function testGetQuickEmail() {
3132 $this->getQuickSearchSampleData();
1ca22999 3133 $loggedInContactID = $this->createLoggedInUser();
46312f7d 3134 $result = $this->callAPISuccess('contact', 'getquick', [
e9e27a80 3135 'name' => 'c',
46312f7d 3136 ]);
3137 $expectedData = [
613643e0 3138 'A Bobby, Bobby :: bob@bobby.com',
e9e27a80 3139 'Bob, Bob :: bob@bob.com',
3140 'C Bobby, Bobby',
e9e27a80 3141 'H Bobby, Bobby :: bob@h.com',
1ca22999 3142 'Second Domain',
46312f7d 3143 $this->callAPISuccessGetValue('Contact', ['id' => $loggedInContactID, 'return' => 'last_name']) . ', Logged In :: anthony_anderson@civicrm.org',
3144 ];
1ca22999 3145 $this->assertEquals(6, $result['count']);
e9e27a80 3146 foreach ($expectedData as $index => $value) {
3147 $this->assertEquals($value, $result['values'][$index]['data']);
3148 }
46312f7d 3149 $result = $this->callAPISuccess('contact', 'getquick', [
7f6f3df1 3150 'name' => 'h.',
46312f7d 3151 ]);
3152 $expectedData = [
7f6f3df1 3153 'H Bobby, Bobby :: bob@h.com',
46312f7d 3154 ];
7f6f3df1 3155 foreach ($expectedData as $index => $value) {
3156 $this->assertEquals($value, $result['values'][$index]['data']);
3157 }
46312f7d 3158 $this->callAPISuccess('Setting', 'create', ['includeWildCardInName' => FALSE]);
3159 $result = $this->callAPISuccess('contact', 'getquick', [
7f6f3df1 3160 'name' => 'h.',
46312f7d 3161 ]);
3162 $this->callAPISuccess('Setting', 'create', ['includeWildCardInName' => TRUE]);
7f6f3df1 3163 $this->assertEquals(0, $result['count']);
e9e27a80 3164 }
3165
c37a2d66 3166 /**
3167 * Test that getquick returns contacts with an exact first name match first.
3168 */
3169 public function testGetQuickEmailACL() {
3170 $this->getQuickSearchSampleData();
1ca22999 3171 $loggedInContactID = $this->createLoggedInUser();
46312f7d 3172 CRM_Core_Config::singleton()->userPermissionClass->permissions = [];
3173 $result = $this->callAPISuccess('contact', 'getquick', [
c37a2d66 3174 'name' => 'c',
46312f7d 3175 ]);
c37a2d66 3176 $this->assertEquals(0, $result['count']);
3177
46312f7d 3178 $this->hookClass->setHook('civicrm_aclWhereClause', [$this, 'aclWhereNoBobH']);
1ca22999 3179 CRM_Contact_BAO_Contact_Permission::cache($loggedInContactID, CRM_Core_Permission::VIEW, TRUE);
46312f7d 3180 $result = $this->callAPISuccess('contact', 'getquick', [
c37a2d66 3181 'name' => 'c',
46312f7d 3182 ]);
1ca22999 3183
3184 // Without the acl it would be 6 like the previous email getquick test.
3185 $this->assertEquals(5, $result['count']);
46312f7d 3186 $expectedData = [
613643e0 3187 'A Bobby, Bobby :: bob@bobby.com',
c37a2d66 3188 'Bob, Bob :: bob@bob.com',
3189 'C Bobby, Bobby',
1ca22999 3190 'Second Domain',
46312f7d 3191 $this->callAPISuccessGetValue('Contact', ['id' => $loggedInContactID, 'return' => 'last_name']) . ', Logged In :: anthony_anderson@civicrm.org',
3192 ];
c37a2d66 3193 foreach ($expectedData as $index => $value) {
3194 $this->assertEquals($value, $result['values'][$index]['data']);
3195 }
3196 }
3197
2baa1e00 3198 /**
3199 * Test that getquick returns contacts with an exact first name match first.
3200 */
3201 public function testGetQuickExternalID() {
3202 $this->getQuickSearchSampleData();
46312f7d 3203 $result = $this->callAPISuccess('contact', 'getquick', [
2baa1e00 3204 'name' => 'b',
3205 'field_name' => 'external_identifier',
3206 'table_name' => 'cc',
46312f7d 3207 ]);
2baa1e00 3208 $this->assertEquals(0, $result['count']);
46312f7d 3209 $result = $this->callAPISuccess('contact', 'getquick', [
2baa1e00 3210 'name' => 'abc',
3211 'field_name' => 'external_identifier',
3212 'table_name' => 'cc',
46312f7d 3213 ]);
2baa1e00 3214 $this->assertEquals(1, $result['count']);
3215 $this->assertEquals('Bob, Bob', $result['values'][0]['sort_name']);
3216 }
3217
3218 /**
3219 * Test that getquick returns contacts with an exact first name match first.
3220 */
3221 public function testGetQuickID() {
1ca22999 3222 $max = CRM_Core_DAO::singleValueQuery("SELECT max(id) FROM civicrm_contact");
2baa1e00 3223 $this->getQuickSearchSampleData();
46312f7d 3224 $result = $this->callAPISuccess('contact', 'getquick', [
1ca22999 3225 'name' => $max + 2,
2baa1e00 3226 'field_name' => 'id',
3227 'table_name' => 'cc',
46312f7d 3228 ]);
2baa1e00 3229 $this->assertEquals(1, $result['count']);
613643e0 3230 $this->assertEquals('E Bobby, Bobby', $result['values'][0]['sort_name']);
46312f7d 3231 $result = $this->callAPISuccess('contact', 'getquick', [
1ca22999 3232 'name' => $max + 2,
2baa1e00 3233 'field_name' => 'contact_id',
3234 'table_name' => 'cc',
46312f7d 3235 ]);
2baa1e00 3236 $this->assertEquals(1, $result['count']);
613643e0 3237 $this->assertEquals('E Bobby, Bobby', $result['values'][0]['sort_name']);
2baa1e00 3238 }
3239
3240 /**
3241 * Test that getquick returns contacts with an exact first name match first.
ef3fd279 3242 *
3243 * Depending on the setting the sort name sort might click in next or not - test!
2baa1e00 3244 */
3245 public function testGetQuickFirstName() {
3246 $this->getQuickSearchSampleData();
46312f7d 3247 $this->callAPISuccess('Setting', 'create', ['includeOrderByClause' => TRUE]);
3248 $result = $this->callAPISuccess('contact', 'getquick', [
2baa1e00 3249 'name' => 'Bob',
3250 'field_name' => 'first_name',
3251 'table_name' => 'cc',
46312f7d 3252 ]);
3253 $expected = [
613643e0 3254 'Aadvark, Bob',
e9e27a80 3255 'Bob, Bob',
3256 'K Bobby, Bob',
3257 'A Bobby, Bobby',
46312f7d 3258 ];
e9e27a80 3259
3260 foreach ($expected as $index => $value) {
3261 $this->assertEquals($value, $result['values'][$index]['sort_name']);
3262 }
46312f7d 3263 $this->callAPISuccess('Setting', 'create', ['includeOrderByClause' => FALSE]);
3264 $result = $this->callAPISuccess('contact', 'getquick', ['name' => 'bob']);
08f4ab8d 3265 $this->assertEquals('Bob, Bob', $result['values'][0]['sort_name']);
fae75b58
SL
3266 // This test has been disabled as is proving to be problematic to reproduce due to MySQL sorting issues between different versions
3267 //$this->assertEquals('E Bobby, Bobby', $result['values'][1]['sort_name']);
08f4ab8d 3268 }
3269
1b9c2802 3270 /**
3271 * Test that getquick applies ACLs.
3272 */
3273 public function testGetQuickFirstNameACLs() {
3274 $this->getQuickSearchSampleData();
3275 $userID = $this->createLoggedInUser();
46312f7d 3276 $this->callAPISuccess('Setting', 'create', ['includeOrderByClause' => TRUE, 'search_autocomplete_count' => 15]);
3277 CRM_Core_Config::singleton()->userPermissionClass->permissions = [];
3278 $result = $this->callAPISuccess('contact', 'getquick', [
1b9c2802 3279 'name' => 'Bob',
3280 'field_name' => 'first_name',
3281 'table_name' => 'cc',
46312f7d 3282 ]);
1b9c2802 3283 $this->assertEquals(0, $result['count']);
3284
46312f7d 3285 $this->hookClass->setHook('civicrm_aclWhereClause', [$this, 'aclWhereNoBobH']);
1b9c2802 3286 CRM_Contact_BAO_Contact_Permission::cache($userID, CRM_Core_Permission::VIEW, TRUE);
46312f7d 3287 $result = $this->callAPISuccess('contact', 'getquick', [
1b9c2802 3288 'name' => 'Bob',
3289 'field_name' => 'first_name',
3290 'table_name' => 'cc',
46312f7d 3291 ]);
613643e0 3292 $this->assertEquals('K Bobby, Bob', $result['values'][2]['sort_name']);
1b9c2802 3293 // Without the ACL 9 would be bob@h.com.
613643e0 3294 $this->assertEquals('I Bobby, Bobby', $result['values'][10]['sort_name']);
1b9c2802 3295 }
3296
3297 /**
3298 * Full results returned.
46312f7d 3299 *
1b9c2802 3300 * @implements CRM_Utils_Hook::aclWhereClause
3301 *
3302 * @param string $type
3303 * @param array $tables
3304 * @param array $whereTables
3305 * @param int $contactID
3306 * @param string $where
3307 */
3308 public function aclWhereNoBobH($type, &$tables, &$whereTables, &$contactID, &$where) {
c37a2d66 3309 $where = " (email <> 'bob@h.com' OR email IS NULL) ";
1b9c2802 3310 $whereTables['civicrm_email'] = "LEFT JOIN civicrm_email e ON contact_a.id = e.contact_id";
3311 }
3312
e9e27a80 3313 /**
3314 * Test that getquick returns contacts with an exact last name match first.
3315 */
3316 public function testGetQuickLastName() {
3317 $this->getQuickSearchSampleData();
46312f7d 3318 $this->callAPISuccess('Setting', 'create', ['includeOrderByClause' => TRUE]);
3319 $result = $this->callAPISuccess('contact', 'getquick', [
e9e27a80 3320 'name' => 'Bob',
3321 'field_name' => 'last_name',
3322 'table_name' => 'cc',
46312f7d 3323 ]);
3324 $expected = [
e9e27a80 3325 'Bob, Bob',
3326 'A Bobby, Bobby',
36575b09 3327 'B Bobby, Bobby',
46312f7d 3328 ];
e9e27a80 3329
3330 foreach ($expected as $index => $value) {
3331 $this->assertEquals($value, $result['values'][$index]['sort_name']);
3332 }
46312f7d 3333 $this->callAPISuccess('Setting', 'create', ['includeOrderByClause' => FALSE]);
3334 $result = $this->callAPISuccess('contact', 'getquick', ['name' => 'bob']);
e9e27a80 3335 $this->assertEquals('Bob, Bob :: bob@bob.com', $result['values'][0]['data']);
3336 }
3337
3338 /**
3339 * Test that getquick returns contacts by city.
3340 */
3341 public function testGetQuickCity() {
3342 $this->getQuickSearchSampleData();
46312f7d 3343 $result = $this->callAPISuccess('contact', 'getquick', [
e9e27a80 3344 'name' => 'o',
3345 'field_name' => 'city',
3346 'table_name' => 'sts',
46312f7d 3347 ]);
e9e27a80 3348 $this->assertEquals('B Bobby, Bobby :: Toronto', $result['values'][0]['data']);
46312f7d 3349 $result = $this->callAPISuccess('contact', 'getquick', [
e9e27a80 3350 'name' => 'n',
3351 'field_name' => 'city',
3352 'table_name' => 'sts',
46312f7d 3353 ]);
e9e27a80 3354 $this->assertEquals('B Bobby, Bobby :: Toronto', $result['values'][0]['data']);
3355 $this->assertEquals('C Bobby, Bobby :: Whanganui', $result['values'][1]['data']);
3356 }
3357
08f4ab8d 3358 /**
3359 * Set up some sample data for testing quicksearch.
3360 */
3361 public function getQuickSearchSampleData() {
46312f7d 3362 $contacts = [
3363 ['first_name' => 'Bob', 'last_name' => 'Bob', 'external_identifier' => 'abc', 'email' => 'bob@bob.com'],
3364 ['first_name' => 'Bobby', 'last_name' => 'E Bobby', 'external_identifier' => 'abcd'],
3365 [
36575b09 3366 'first_name' => 'Bobby',
3367 'last_name' => 'B Bobby',
3368 'external_identifier' => 'bcd',
46312f7d 3369 'api.address.create' => [
36575b09 3370 'street_address' => 'Sesame Street',
3371 'city' => 'Toronto',
3372 'location_type_id' => 1,
46312f7d 3373 ],
3374 ],
3375 [
36575b09 3376 'first_name' => 'Bobby',
3377 'last_name' => 'C Bobby',
3378 'external_identifier' => 'bcde',
46312f7d 3379 'api.address.create' => [
36575b09 3380 'street_address' => 'Te huarahi',
3381 'city' => 'Whanganui',
3382 'location_type_id' => 1,
46312f7d 3383 ],
3384 ],
3385 ['first_name' => 'Bobby', 'last_name' => 'D Bobby', 'external_identifier' => 'efg'],
3386 ['first_name' => 'Bobby', 'last_name' => 'A Bobby', 'external_identifier' => 'hij', 'email' => 'bob@bobby.com'],
3387 ['first_name' => 'Bobby', 'last_name' => 'F Bobby', 'external_identifier' => 'klm'],
3388 ['first_name' => 'Bobby', 'last_name' => 'G Bobby', 'external_identifier' => 'nop'],
3389 ['first_name' => 'Bobby', 'last_name' => 'H Bobby', 'external_identifier' => 'qrs', 'email' => 'bob@h.com'],
3390 ['first_name' => 'Bobby', 'last_name' => 'I Bobby'],
3391 ['first_name' => 'Bobby', 'last_name' => 'J Bobby'],
3392 ['first_name' => 'Bob', 'last_name' => 'K Bobby', 'external_identifier' => 'bcdef'],
3393 ['first_name' => 'Bob', 'last_name' => 'Aadvark'],
3394 ];
08f4ab8d 3395 foreach ($contacts as $type => $contact) {
3396 $contact['contact_type'] = 'Individual';
3397 $this->callAPISuccess('Contact', 'create', $contact);
3398 }
3399 }
3400
b2130237 3401 /**
381fa321 3402 * Test get ref api - gets a list of references to an entity.
b2130237 3403 */
00be9182 3404 public function testGetReferenceCounts() {
46312f7d 3405 $result = $this->callAPISuccess('Contact', 'create', [
9c8096cb
TO
3406 'first_name' => 'Testily',
3407 'last_name' => 'McHaste',
3408 'contact_type' => 'Individual',
46312f7d 3409 'api.Address.replace' => [
3410 'values' => [],
3411 ],
3412 'api.Email.replace' => [
3413 'values' => [
3414 [
9c8096cb
TO
3415 'email' => 'spam@dev.null',
3416 'is_primary' => 0,
3417 'location_type_id' => 1,
46312f7d 3418 ],
3419 ],
3420 ],
3421 'api.Phone.replace' => [
3422 'values' => [
3423 [
9c8096cb
TO
3424 'phone' => '234-567-0001',
3425 'is_primary' => 1,
3426 'location_type_id' => 1,
46312f7d 3427 ],
3428 [
9c8096cb
TO
3429 'phone' => '234-567-0002',
3430 'is_primary' => 0,
3431 'location_type_id' => 1,
46312f7d 3432 ],
3433 ],
3434 ],
3435 ]);
9c8096cb
TO
3436
3437 //$dao = new CRM_Contact_BAO_Contact();
3438 //$dao->id = $result['id'];
3439 //$this->assertTrue((bool) $dao->find(TRUE));
3440 //
3441 //$refCounts = $dao->getReferenceCounts();
3442 //$this->assertTrue(is_array($refCounts));
3443 //$refCountsIdx = CRM_Utils_Array::index(array('name'), $refCounts);
3444
46312f7d 3445 $refCounts = $this->callAPISuccess('Contact', 'getrefcount', [
21dfd5f5 3446 'id' => $result['id'],
46312f7d 3447 ]);
3448 $refCountsIdx = CRM_Utils_Array::index(['name'], $refCounts['values']);
9c8096cb
TO
3449
3450 $this->assertEquals(1, $refCountsIdx['sql:civicrm_email:contact_id']['count']);
3451 $this->assertEquals('civicrm_email', $refCountsIdx['sql:civicrm_email:contact_id']['table']);
3452 $this->assertEquals(2, $refCountsIdx['sql:civicrm_phone:contact_id']['count']);
3453 $this->assertEquals('civicrm_phone', $refCountsIdx['sql:civicrm_phone:contact_id']['table']);
3454 $this->assertTrue(!isset($refCountsIdx['sql:civicrm_address:contact_id']));
3455 }
3456
701a69da 3457 /**
3458 * Test the use of sql operators.
46312f7d 3459 *
2d932085 3460 * @param int $version
46312f7d 3461 *
2d932085 3462 * @dataProvider versionThreeAndFour
701a69da 3463 */
2d932085
CW
3464 public function testSQLOperatorsOnContactAPI($version) {
3465 $this->_apiversion = $version;
a75c13cc
EM
3466 $this->individualCreate();
3467 $this->organizationCreate();
3468 $this->householdCreate();
46312f7d 3469 $contacts = $this->callAPISuccess('contact', 'get', ['legal_name' => ['IS NOT NULL' => TRUE]]);
a75c13cc 3470 $this->assertEquals($contacts['count'], CRM_Core_DAO::singleValueQuery('select count(*) FROM civicrm_contact WHERE legal_name IS NOT NULL'));
46312f7d 3471 $contacts = $this->callAPISuccess('contact', 'get', ['legal_name' => ['IS NULL' => TRUE]]);
a75c13cc
EM
3472 $this->assertEquals($contacts['count'], CRM_Core_DAO::singleValueQuery('select count(*) FROM civicrm_contact WHERE legal_name IS NULL'));
3473 }
9bee5ea2 3474
9bee5ea2 3475 /**
fe482240 3476 * CRM-14743 - test api respects search operators.
46312f7d 3477 *
2d932085 3478 * @param int $version
46312f7d 3479 *
2d932085 3480 * @dataProvider versionThreeAndFour
9bee5ea2 3481 */
2d932085
CW
3482 public function testGetModifiedDateByOperators($version) {
3483 $this->_apiversion = $version;
9bee5ea2
EM
3484 $preExistingContactCount = CRM_Core_DAO::singleValueQuery('select count(*) FROM civicrm_contact');
3485 $contact1 = $this->individualCreate();
3486 $sql = "UPDATE civicrm_contact SET created_date = '2012-01-01', modified_date = '2013-01-01' WHERE id = " . $contact1;
3487 CRM_Core_DAO::executeQuery($sql);
3488 $contact2 = $this->individualCreate();
3489 $sql = "UPDATE civicrm_contact SET created_date = '2012-02-01', modified_date = '2013-02-01' WHERE id = " . $contact2;
3490 CRM_Core_DAO::executeQuery($sql);
3491 $contact3 = $this->householdCreate();
3492 $sql = "UPDATE civicrm_contact SET created_date = '2012-03-01', modified_date = '2013-03-01' WHERE id = " . $contact3;
3493 CRM_Core_DAO::executeQuery($sql);
46312f7d 3494 $contacts = $this->callAPISuccess('contact', 'get', ['modified_date' => ['<' => '2014-01-01']]);
9bee5ea2 3495 $this->assertEquals($contacts['count'], 3);
46312f7d 3496 $contacts = $this->callAPISuccess('contact', 'get', ['modified_date' => ['>' => '2014-01-01']]);
9bee5ea2
EM
3497 $this->assertEquals($contacts['count'], $preExistingContactCount);
3498 }
2134e310 3499
2134e310 3500 /**
fe482240 3501 * CRM-14743 - test api respects search operators.
46312f7d 3502 *
2d932085 3503 * @param int $version
46312f7d 3504 *
2d932085 3505 * @dataProvider versionThreeAndFour
2134e310 3506 */
2d932085
CW
3507 public function testGetCreatedDateByOperators($version) {
3508 $this->_apiversion = $version;
2134e310
EM
3509 $preExistingContactCount = CRM_Core_DAO::singleValueQuery('select count(*) FROM civicrm_contact');
3510 $contact1 = $this->individualCreate();
3511 $sql = "UPDATE civicrm_contact SET created_date = '2012-01-01' WHERE id = " . $contact1;
3512 CRM_Core_DAO::executeQuery($sql);
3513 $contact2 = $this->individualCreate();
3514 $sql = "UPDATE civicrm_contact SET created_date = '2012-02-01' WHERE id = " . $contact2;
3515 CRM_Core_DAO::executeQuery($sql);
3516 $contact3 = $this->householdCreate();
3517 $sql = "UPDATE civicrm_contact SET created_date = '2012-03-01' WHERE id = " . $contact3;
3518 CRM_Core_DAO::executeQuery($sql);
46312f7d 3519 $contacts = $this->callAPISuccess('contact', 'get', ['created_date' => ['<' => '2014-01-01']]);
2134e310 3520 $this->assertEquals($contacts['count'], 3);
46312f7d 3521 $contacts = $this->callAPISuccess('contact', 'get', ['created_date' => ['>' => '2014-01-01']]);
2134e310
EM
3522 $this->assertEquals($contacts['count'], $preExistingContactCount);
3523 }
e5fccefb
EM
3524
3525 /**
fe482240 3526 * CRM-14263 check that API is not affected by search profile related bug.
e5fccefb 3527 */
5896d037 3528 public function testReturnCityProfile() {
e5fccefb
EM
3529 $contactID = $this->individualCreate();
3530 CRM_Core_Config::singleton()->defaultSearchProfileID = 1;
46312f7d 3531 $this->callAPISuccess('address', 'create', [
92915c55
TO
3532 'contact_id' => $contactID,
3533 'city' => 'Cool City',
3534 'location_type_id' => 1,
46312f7d 3535 ]);
3536 $result = $this->callAPISuccess('contact', 'get', ['city' => 'Cool City', 'return' => 'contact_type']);
e5fccefb
EM
3537 $this->assertEquals(1, $result['count']);
3538 }
eaa112a5 3539
eaa112a5 3540 /**
701a69da 3541 * CRM-15443 - ensure getlist api does not return deleted contacts.
eaa112a5 3542 */
00be9182 3543 public function testGetlistExcludeConditions() {
9436d5d5 3544 $name = 'Scarabée';
46312f7d 3545 $contact = $this->individualCreate(['last_name' => $name]);
3546 $this->individualCreate(['last_name' => $name, 'is_deceased' => 1]);
3547 $this->individualCreate(['last_name' => $name, 'is_deleted' => 1]);
381fa321 3548 // We should get all but the deleted contact.
46312f7d 3549 $result = $this->callAPISuccess('contact', 'getlist', ['input' => $name]);
ba4a1892 3550 $this->assertEquals(2, $result['count']);
381fa321 3551 // Force-exclude the deceased contact.
46312f7d 3552 $result = $this->callAPISuccess('contact', 'getlist', [
92915c55 3553 'input' => $name,
46312f7d 3554 'params' => ['is_deceased' => 0],
3555 ]);
ba4a1892
TM
3556 $this->assertEquals(1, $result['count']);
3557 $this->assertEquals($contact, $result['values'][0]['id']);
eaa112a5 3558 }
92776611
CW
3559
3560 /**
fe482240 3561 * Test contact getactions.
92776611 3562 */
00be9182 3563 public function testGetActions() {
92776611 3564 $description = "Getting the available actions for an entity.";
46312f7d 3565 $result = $this->callAPIAndDocument($this->_entity, 'getactions', [], __FUNCTION__, __FILE__, $description);
3566 $expected = [
92776611
CW
3567 'create',
3568 'delete',
3569 'get',
3570 'getactions',
3571 'getcount',
3572 'getfields',
3573 'getlist',
3574 'getoptions',
3575 'getquick',
3576 'getrefcount',
3577 'getsingle',
3578 'getvalue',
3579 'merge',
3580 'proximity',
3581 'replace',
3582 'setvalue',
3583 'update',
46312f7d 3584 ];
3585 $deprecated = [
92776611
CW
3586 'update',
3587 'getquick',
46312f7d 3588 ];
92776611
CW
3589 foreach ($expected as $action) {
3590 $this->assertTrue(in_array($action, $result['values']), "Expected action $action");
3591 }
3592 foreach ($deprecated as $action) {
3593 $this->assertArrayKeyExists($action, $result['deprecated']);
3594 }
3595 }
96025800 3596
ffe87781 3597 /**
3598 * Test the duplicate check function.
3599 */
3600 public function testDuplicateCheck() {
46312f7d 3601 $harry = [
ffe87781 3602 'first_name' => 'Harry',
3603 'last_name' => 'Potter',
3604 'email' => 'harry@hogwarts.edu',
3605 'contact_type' => 'Individual',
46312f7d 3606 ];
fedc3428 3607 $this->callAPISuccess('Contact', 'create', $harry);
46312f7d 3608 $result = $this->callAPISuccess('Contact', 'duplicatecheck', [
fedc3428 3609 'match' => $harry,
46312f7d 3610 ]);
ffe87781 3611
3612 $this->assertEquals(1, $result['count']);
46312f7d 3613 $result = $this->callAPISuccess('Contact', 'duplicatecheck', [
3614 'match' => [
ffe87781 3615 'first_name' => 'Harry',
3616 'last_name' => 'Potter',
3617 'email' => 'no5@privet.drive',
3618 'contact_type' => 'Individual',
46312f7d 3619 ],
3620 ]);
ffe87781 3621 $this->assertEquals(0, $result['count']);
46312f7d 3622 $this->callAPIFailure('Contact', 'create', array_merge($harry, ['dupe_check' => 1]));
ffe87781 3623 }
3624
a2dd33d3 3625 /**
3626 * Test the duplicate check function.
3627 */
3628 public function testDuplicateCheckRuleNotReserved() {
46312f7d 3629 $harry = [
a2dd33d3 3630 'first_name' => 'Harry',
3631 'last_name' => 'Potter',
3632 'email' => 'harry@hogwarts.edu',
3633 'contact_type' => 'Individual',
46312f7d 3634 ];
3635 $defaultRule = $this->callAPISuccess('RuleGroup', 'getsingle', ['used' => 'Unsupervised', 'is_reserved' => 1]);
3636 $this->callAPISuccess('RuleGroup', 'create', ['id' => $defaultRule['id'], 'is_reserved' => 0]);
a2dd33d3 3637 $this->callAPISuccess('Contact', 'create', $harry);
46312f7d 3638 $result = $this->callAPISuccess('Contact', 'duplicatecheck', [
a2dd33d3 3639 'match' => $harry,
46312f7d 3640 ]);
a2dd33d3 3641
3642 $this->assertEquals(1, $result['count']);
46312f7d 3643 $this->callAPISuccess('RuleGroup', 'create', ['id' => $defaultRule['id'], 'is_reserved' => 1]);
a2dd33d3 3644 }
3645
3646 /**
3647 * Test variants on retrieving contact by type.
3648 */
46b3417a 3649 public function testGetByContactType() {
46312f7d 3650 $individual = $this->callAPISuccess('Contact', 'create', [
46b3417a
CW
3651 'email' => 'individual@test.com',
3652 'contact_type' => 'Individual',
46312f7d 3653 ]);
3654 $household = $this->callAPISuccess('Contact', 'create', [
46b3417a
CW
3655 'household_name' => 'household@test.com',
3656 'contact_type' => 'Household',
46312f7d 3657 ]);
3658 $organization = $this->callAPISuccess('Contact', 'create', [
46b3417a
CW
3659 'organization_name' => 'organization@test.com',
3660 'contact_type' => 'Organization',
46312f7d 3661 ]);
46b3417a 3662 // Test with id - getsingle will throw an exception if not found
46312f7d 3663 $this->callAPISuccess('Contact', 'getsingle', [
46b3417a
CW
3664 'id' => $individual['id'],
3665 'contact_type' => 'Individual',
46312f7d 3666 ]);
3667 $this->callAPISuccess('Contact', 'getsingle', [
46b3417a 3668 'id' => $individual['id'],
46312f7d 3669 'contact_type' => ['IN' => ['Individual']],
46b3417a 3670 'return' => 'id',
46312f7d 3671 ]);
3672 $this->callAPISuccess('Contact', 'getsingle', [
46b3417a 3673 'id' => $organization['id'],
46312f7d 3674 'contact_type' => ['IN' => ['Individual', 'Organization']],
3675 ]);
46b3417a 3676 // Test as array
46312f7d 3677 $result = $this->callAPISuccess('Contact', 'get', [
3678 'contact_type' => ['IN' => ['Individual', 'Organization']],
3679 'options' => ['limit' => 0],
46b3417a 3680 'return' => 'id',
46312f7d 3681 ]);
46b3417a
CW
3682 $this->assertContains($organization['id'], array_keys($result['values']));
3683 $this->assertContains($individual['id'], array_keys($result['values']));
3684 $this->assertNotContains($household['id'], array_keys($result['values']));
3685 // Test as string
46312f7d 3686 $result = $this->callAPISuccess('Contact', 'get', [
46b3417a 3687 'contact_type' => 'Household',
46312f7d 3688 'options' => ['limit' => 0],
46b3417a 3689 'return' => 'id',
46312f7d 3690 ]);
46b3417a
CW
3691 $this->assertNotContains($organization['id'], array_keys($result['values']));
3692 $this->assertNotContains($individual['id'], array_keys($result['values']));
3693 $this->assertContains($household['id'], array_keys($result['values']));
3694 }
3695
12d73bba 3696 /**
3697 * Test merging 2 contacts.
5ea06a7b 3698 *
3699 * Someone kindly bequethed us the legacy of mixed up use of main_id & other_id
3700 * in the params for contact.merge api.
3701 *
3702 * This test protects that legacy.
12d73bba 3703 */
5ea06a7b 3704 public function testMergeBizzareOldParams() {
3705 $this->createLoggedInUser();
12d73bba 3706 $otherContact = $this->callAPISuccess('contact', 'create', $this->_params);
3707 $mainContact = $this->callAPISuccess('contact', 'create', $this->_params);
46312f7d 3708 $this->callAPISuccess('contact', 'merge', [
5ea06a7b 3709 'main_id' => $mainContact['id'],
3710 'other_id' => $otherContact['id'],
46312f7d 3711 ]);
12d73bba 3712 $contacts = $this->callAPISuccess('contact', 'get', $this->_params);
3713 $this->assertEquals($otherContact['id'], $contacts['id']);
5ea06a7b 3714 }
3715
3716 /**
3717 * Test merging 2 contacts.
3718 */
3719 public function testMerge() {
3720 $this->createLoggedInUser();
3721 $otherContact = $this->callAPISuccess('contact', 'create', $this->_params);
3722 $retainedContact = $this->callAPISuccess('contact', 'create', $this->_params);
46312f7d 3723 $this->callAPISuccess('contact', 'merge', [
5ea06a7b 3724 'to_keep_id' => $retainedContact['id'],
3725 'to_remove_id' => $otherContact['id'],
3726 'auto_flip' => FALSE,
46312f7d 3727 ]);
5ea06a7b 3728
3729 $contacts = $this->callAPISuccess('contact', 'get', $this->_params);
3730 $this->assertEquals($retainedContact['id'], $contacts['id']);
46312f7d 3731 $activity = $this->callAPISuccess('Activity', 'getsingle', [
5ea06a7b 3732 'target_contact_id' => $retainedContact['id'],
3733 'activity_type_id' => 'Contact Merged',
46312f7d 3734 ]);
5ea06a7b 3735 $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($activity['activity_date_time'])));
46312f7d 3736 $activity2 = $this->callAPISuccess('Activity', 'getsingle', [
f00283b5 3737 'target_contact_id' => $otherContact['id'],
3738 'activity_type_id' => 'Contact Deleted by Merge',
46312f7d 3739 ]);
f00283b5 3740 $this->assertEquals($activity['id'], $activity2['parent_id']);
46312f7d 3741 $this->assertEquals('Normal', civicrm_api3('option_value', 'getvalue', [
f00283b5 3742 'value' => $activity['priority_id'],
3743 'return' => 'label',
3744 'option_group_id' => 'priority',
46312f7d 3745 ]));
12d73bba 3746
3747 }
3748
119664d6 3749 /**
3750 * Test merging 2 contacts with custom fields.
3751 *
3752 * @throws \Exception
3753 */
3754 public function testMergeCustomFields() {
3755 $contact1 = $this->individualCreate();
1600a9c0 3756 // Not sure this is quite right but it does get it into the file table
119664d6 3757 $file = $this->callAPISuccess('Attachment', 'create', [
1600a9c0 3758 'name' => 'header.txt',
3759 'mime_type' => 'text/plain',
3760 'description' => 'My test description',
3761 'content' => 'My test content',
3762 'entity_table' => 'civicrm_contact',
3763 'entity_id' => $contact1,
119664d6 3764 ]);
119664d6 3765
3766 $this->createCustomGroupWithFieldsOfAllTypes();
3767 $fileField = $this->getCustomFieldName('file');
3768 $linkField = $this->getCustomFieldName('link');
3769 $dateField = $this->getCustomFieldName('select_date');
3770 $selectField = $this->getCustomFieldName('select_string');
3771 $countryField = $this->getCustomFieldName('country');
3772
3773 $countriesByName = array_flip(CRM_Core_PseudoConstant::country(FALSE, FALSE));
3774 $customFieldValues = [
3775 // @todo fix the fatal bug on this & uncomment - see dev/core#723
1600a9c0 3776 $fileField => $file['id'],
119664d6 3777 $linkField => 'http://example.org',
3778 $dateField => '2018-01-01 17:10:56',
3779 $selectField => 'G',
3780 // Currently broken.
3781 //$countryField => $countriesByName['New Zealand'],
3782 ];
3783 $this->callAPISuccess('Contact', 'create', array_merge([
3784 'id' => $contact1,
3785 ], $customFieldValues));
3786
3787 $contact2 = $this->individualCreate();
3788 $this->callAPISuccess('contact', 'merge', [
3789 'to_keep_id' => $contact2,
3790 'to_remove_id' => $contact1,
3791 'auto_flip' => FALSE,
3792 ]);
3793 $contact = $this->callAPISuccessGetSingle('Contact', ['id' => $contact2, 'return' => array_keys($customFieldValues)]);
1600a9c0 3794 $this->assertEquals($contact2, CRM_Core_DAO::singleValueQuery('SELECT entity_id FROM civicrm_entity_file WHERE file_id = ' . $file['id']));
119664d6 3795 foreach ($customFieldValues as $key => $value) {
3796 $this->assertEquals($value, $contact[$key]);
3797 }
3798 }
3799
734cd0d5 3800 /**
3801 * Test retrieving merged contacts.
3802 *
3803 * The goal here is to start with a contact deleted by merged and find out the contact that is the current version of them.
e07cf53e 3804 *
3805 * @throws \CRM_Core_Exception
734cd0d5 3806 */
3807 public function testMergedGet() {
3808 $this->contactIDs[] = $this->individualCreate();
3809 $this->contactIDs[] = $this->individualCreate();
3810 $this->contactIDs[] = $this->individualCreate();
3811 $this->contactIDs[] = $this->individualCreate();
3812
3813 // First do an 'unnatural merge' - they 'like to merge into the lowest but this will mean that contact 0 merged to contact [3].
3814 // When the batch merge runs.... the new lowest contact is contact[1]. All contacts will merge into that contact,
3815 // including contact[3], resulting in only 3 existing at the end. For each contact the correct answer to 'who did I eventually
3816 // wind up being should be [1]
3817 $this->callAPISuccess('Contact', 'merge', ['to_remove_id' => $this->contactIDs[0], 'to_keep_id' => $this->contactIDs[3]]);
3818
3819 $this->callAPISuccess('Job', 'process_batch_merge', []);
3820 foreach ($this->contactIDs as $contactID) {
3821 if ($contactID === $this->contactIDs[1]) {
3822 continue;
3823 }
3824 $result = $this->callAPIAndDocument('Contact', 'getmergedto', ['sequential' => 1, 'contact_id' => $contactID], __FUNCTION__, __FILE__);
3825 $this->assertEquals(1, $result['count']);
3826 $this->assertEquals($this->contactIDs[1], $result['values'][0]['id']);
3827 }
3828
3829 $result = $this->callAPIAndDocument('Contact', 'getmergedfrom', ['contact_id' => $this->contactIDs[1]], __FUNCTION__, __FILE__)['values'];
3830 $mergedContactIds = array_merge(array_diff($this->contactIDs, [$this->contactIDs[1]]));
3831 $this->assertEquals($mergedContactIds, array_keys($result));
3832 }
3833
4d834a99 3834 /**
3835 * Test merging 2 contacts with delete to trash off.
3836 *
3837 * We are checking that there is no error due to attempting to add an activity for the
3838 * deleted contact.
3839 *
3840 * CRM-18307
3841 */
3842 public function testMergeNoTrash() {
3843 $this->createLoggedInUser();
46312f7d 3844 $this->callAPISuccess('Setting', 'create', ['contact_undelete' => FALSE]);
4d834a99 3845 $otherContact = $this->callAPISuccess('contact', 'create', $this->_params);
3846 $retainedContact = $this->callAPISuccess('contact', 'create', $this->_params);
46312f7d 3847 $this->callAPISuccess('contact', 'merge', [
4d834a99 3848 'to_keep_id' => $retainedContact['id'],
3849 'to_remove_id' => $otherContact['id'],
3850 'auto_flip' => FALSE,
46312f7d 3851 ]);
3852 $this->callAPISuccess('Setting', 'create', ['contact_undelete' => TRUE]);
4d834a99 3853 }
3854
00ed3e04
CB
3855 /**
3856 * Ensure format with return=group shows comma-separated group IDs.
3857 *
3858 * CRM-19426
3859 */
3860 public function testContactGetReturnGroup() {
3861 // Set up a contact, asser that they were created.
46312f7d 3862 $contact_params = [
00ed3e04
CB
3863 'contact_type' => 'Individual',
3864 'first_name' => 'Test',
3865 'last_name' => 'Groupmember',
3866 'email' => 'test@example.org',
46312f7d 3867 ];
00ed3e04
CB
3868 $create_contact = $this->callApiSuccess('Contact', 'create', $contact_params);
3869 $this->assertEquals(0, $create_contact['is_error']);
3870 $this->assertInternalType('int', $create_contact['id']);
3871
3872 $created_contact_id = $create_contact['id'];
3873
3874 // Set up multiple groups, add the contact to the groups.
46312f7d 3875 $test_groups = ['Test group A', 'Test group B'];
00ed3e04
CB
3876 foreach ($test_groups as $title) {
3877 // Use this contact as group owner, since we know they exist.
46312f7d 3878 $group_params = [
00ed3e04
CB
3879 'title' => $title,
3880 'created_id' => $created_contact_id,
46312f7d 3881 ];
00ed3e04
CB
3882 $create_group = $this->callApiSuccess('Group', 'create', $group_params);
3883 $this->assertEquals(0, $create_group['is_error']);
3884 $this->assertInternalType('int', $create_group['id']);
3885
3886 $created_group_ids[] = $create_group['id'];
3887
3888 // Add contact to the new group.
46312f7d 3889 $group_contact_params = [
00ed3e04
CB
3890 'contact_id' => $created_contact_id,
3891 'group_id' => $create_group['id'],
46312f7d 3892 ];
00ed3e04
CB
3893 $create_group_contact = $this->callApiSuccess('GroupContact', 'create', $group_contact_params);
3894 $this->assertEquals(0, $create_group_contact['is_error']);
3895 $this->assertInternalType('int', $create_group_contact['added']);
3896 }
3897
3898 // Use the Contact,get API to retrieve the contact
46312f7d 3899 $contact_get_params = [
00ed3e04
CB
3900 'id' => $created_contact_id,
3901 'return' => 'group',
46312f7d 3902 ];
00ed3e04
CB
3903 $contact_get = $this->callApiSuccess('Contact', 'get', $contact_get_params);
3904 $this->assertInternalType('array', $contact_get['values'][$created_contact_id]);
3905 $this->assertInternalType('string', $contact_get['values'][$created_contact_id]['groups']);
3906
3907 // Ensure they are shown as being in each created group.
3908 $contact_group_ids = explode(',', $contact_get['values'][$created_contact_id]['groups']);
3909 foreach ($created_group_ids as $created_group_id) {
3910 $this->assertContains($created_group_id, $contact_group_ids);
3911 }
3912 }
3913
309f98a9
SL
3914 /**
3915 * CRM-20144 Verify that passing title of group works as well as id
0c66b30c
SL
3916 * Tests the following formats
3917 * contact.get group='title1'
3918 * contact.get group=id1
309f98a9
SL
3919 */
3920 public function testContactGetWithGroupTitle() {
3921 // Set up a contact, asser that they were created.
46312f7d 3922 $contact_params = [
309f98a9
SL
3923 'contact_type' => 'Individual',
3924 'first_name' => 'Test2',
3925 'last_name' => 'Groupmember',
3926 'email' => 'test@example.org',
46312f7d 3927 ];
309f98a9
SL
3928 $create_contact = $this->callApiSuccess('Contact', 'create', $contact_params);
3929 $created_contact_id = $create_contact['id'];
3930 // Set up multiple groups, add the contact to the groups.
46312f7d 3931 $test_groups = ['Test group C', 'Test group D'];
309f98a9 3932 foreach ($test_groups as $title) {
46312f7d 3933 $group_params = [
309f98a9
SL
3934 'title' => $title,
3935 'created_id' => $created_contact_id,
46312f7d 3936 ];
309f98a9
SL
3937 $create_group = $this->callApiSuccess('Group', 'create', $group_params);
3938 $created_group_id = $create_group['id'];
3939
3940 // Add contact to the new group.
46312f7d 3941 $group_contact_params = [
309f98a9
SL
3942 'contact_id' => $created_contact_id,
3943 'group_id' => $create_group['id'],
46312f7d 3944 ];
6d054a8e 3945 $this->callApiSuccess('GroupContact', 'create', $group_contact_params);
46312f7d 3946 $contact_get = $this->callAPISuccess('contact', 'get', ['group' => $title, 'return' => 'group']);
309f98a9
SL
3947 $this->assertEquals(1, $contact_get['count']);
3948 $this->assertEquals($created_contact_id, $contact_get['id']);
3949 $contact_groups = explode(',', $contact_get['values'][$created_contact_id]['groups']);
3950 $this->assertContains((string) $create_group['id'], $contact_groups);
46312f7d 3951 $contact_get2 = $this->callAPISuccess('contact', 'get', ['group' => $created_group_id, 'return' => 'group']);
309f98a9
SL
3952 $this->assertEquals($created_contact_id, $contact_get2['id']);
3953 $contact_groups2 = explode(',', $contact_get2['values'][$created_contact_id]['groups']);
3954 $this->assertContains((string) $create_group['id'], $contact_groups2);
46312f7d 3955 $this->callAPISuccess('group', 'delete', ['id' => $created_group_id]);
309f98a9 3956 }
46312f7d 3957 $this->callAPISuccess('contact', 'delete', ['id' => $created_contact_id, 'skip_undelete' => TRUE]);
309f98a9
SL
3958 }
3959
0c66b30c
SL
3960 /**
3961 * CRM-20144 Verify that passing title of group works as well as id
3962 * Tests the following formats
3963 * contact.get group=array('title1', title1)
3964 * contact.get group=array('IN' => array('title1', 'title2)
3965 */
3966 public function testContactGetWithGroupTitleMultipleGroups() {
d0aa0e47
SL
3967 $description = "Get all from group and display contacts.";
3968 $subFile = "GroupFilterUsingContactAPI";
0c66b30c 3969 // Set up a contact, asser that they were created.
46312f7d 3970 $contact_params = [
0c66b30c
SL
3971 'contact_type' => 'Individual',
3972 'first_name' => 'Test2',
3973 'last_name' => 'Groupmember',
3974 'email' => 'test@example.org',
46312f7d 3975 ];
0c66b30c
SL
3976 $create_contact = $this->callApiSuccess('Contact', 'create', $contact_params);
3977 $created_contact_id = $create_contact['id'];
46312f7d 3978 $createdGroupsTitles = $createdGroupsIds = [];
0c66b30c 3979 // Set up multiple groups, add the contact to the groups.
46312f7d 3980 $test_groups = ['Test group C', 'Test group D'];
0c66b30c 3981 foreach ($test_groups as $title) {
46312f7d 3982 $group_params = [
0c66b30c
SL
3983 'title' => $title,
3984 'created_id' => $created_contact_id,
46312f7d 3985 ];
0c66b30c
SL
3986 $create_group = $this->callApiSuccess('Group', 'create', $group_params);
3987 $created_group_id = $create_group['id'];
3988 $createdGroupsIds[] = $create_group['id'];
3989 $createdGroupTitles[] = $title;
3990 // Add contact to the new group.
46312f7d 3991 $group_contact_params = [
0c66b30c
SL
3992 'contact_id' => $created_contact_id,
3993 'group_id' => $create_group['id'],
46312f7d 3994 ];
0c66b30c
SL
3995 $create_group_contact = $this->callApiSuccess('GroupContact', 'create', $group_contact_params);
3996 }
46312f7d 3997 $contact_get = $this->callAPISuccess('contact', 'get', ['group' => $createdGroupTitles, 'return' => 'group']);
0c66b30c
SL
3998 $this->assertEquals(1, $contact_get['count']);
3999 $this->assertEquals($created_contact_id, $contact_get['id']);
4000 $contact_groups = explode(',', $contact_get['values'][$created_contact_id]['groups']);
4001 foreach ($createdGroupsIds as $id) {
4002 $this->assertContains((string) $id, $contact_groups);
4003 }
46312f7d 4004 $contact_get2 = $this->callAPIAndDocument('contact', 'get', ['group' => ['IN' => $createdGroupTitles]], __FUNCTION__, __FILE__, $description, $subFile);
4005 $contact_get2 = $this->callAPISuccess('contact', 'get', ['group' => ['IN' => $createdGroupTitles], 'return' => 'group']);
0c66b30c
SL
4006 $this->assertEquals($created_contact_id, $contact_get2['id']);
4007 $contact_groups2 = explode(',', $contact_get2['values'][$created_contact_id]['groups']);
4008 foreach ($createdGroupsIds as $id) {
4009 $this->assertContains((string) $id, $contact_groups2);
4010 }
4011 foreach ($createdGroupsIds as $id) {
46312f7d 4012 $this->callAPISuccess('group', 'delete', ['id' => $id]);
0c66b30c 4013 }
46312f7d 4014 $this->callAPISuccess('contact', 'delete', ['id' => $created_contact_id, 'skip_undelete' => TRUE]);
0c66b30c
SL
4015 }
4016
b6b28d93
SL
4017 /**
4018 * CRM-20144 Verify that passing title of group works as well as id
4019 * Tests the following formats
4020 * contact.get group=array('title1' => 1)
4021 * contact.get group=array('titke1' => 1, 'title2' => 1)
4022 * contact.get group=array('id1' => 1)
4023 * contact.get group=array('id1' => 1, id2 => 1)
4024 */
4025 public function testContactGetWithGroupTitleMultipleGroupsLegacyFormat() {
4026 // Set up a contact, asser that they were created.
46312f7d 4027 $contact_params = [
b6b28d93
SL
4028 'contact_type' => 'Individual',
4029 'first_name' => 'Test2',
4030 'last_name' => 'Groupmember',
4031 'email' => 'test@example.org',
46312f7d 4032 ];
b6b28d93
SL
4033 $create_contact = $this->callApiSuccess('Contact', 'create', $contact_params);
4034 $created_contact_id = $create_contact['id'];
46312f7d 4035 $createdGroupsTitles = $createdGroupsIds = [];
b6b28d93 4036 // Set up multiple groups, add the contact to the groups.
46312f7d 4037 $test_groups = ['Test group C', 'Test group D'];
b6b28d93 4038 foreach ($test_groups as $title) {
46312f7d 4039 $group_params = [
b6b28d93
SL
4040 'title' => $title,
4041 'created_id' => $created_contact_id,
46312f7d 4042 ];
b6b28d93
SL
4043 $create_group = $this->callApiSuccess('Group', 'create', $group_params);
4044 $created_group_id = $create_group['id'];
4045 $createdGroupsIds[] = $create_group['id'];
4046 $createdGroupTitles[] = $title;
4047 // Add contact to the new group.
46312f7d 4048 $group_contact_params = [
b6b28d93
SL
4049 'contact_id' => $created_contact_id,
4050 'group_id' => $create_group['id'],
46312f7d 4051 ];
b6b28d93
SL
4052 $create_group_contact = $this->callApiSuccess('GroupContact', 'create', $group_contact_params);
4053 }
46312f7d 4054 $contact_get = $this->callAPISuccess('contact', 'get', ['group' => [$createdGroupTitles[0] => 1], 'return' => 'group']);
b6b28d93
SL
4055 $this->assertEquals(1, $contact_get['count']);
4056 $this->assertEquals($created_contact_id, $contact_get['id']);
4057 $contact_groups = explode(',', $contact_get['values'][$created_contact_id]['groups']);
4058 foreach ($createdGroupsIds as $id) {
4059 $this->assertContains((string) $id, $contact_groups);
4060 }
46312f7d 4061 $contact_get2 = $this->callAPISuccess('contact', 'get', ['group' => [$createdGroupTitles[0] => 1, $createdGroupTitles[1] => 1], 'return' => 'group']);
b6b28d93
SL
4062 $this->assertEquals(1, $contact_get2['count']);
4063 $this->assertEquals($created_contact_id, $contact_get2['id']);
62b8c91c 4064 $contact_groups2 = explode(',', $contact_get2['values'][$created_contact_id]['groups']);
b6b28d93 4065 foreach ($createdGroupsIds as $id) {
62b8c91c 4066 $this->assertContains((string) $id, $contact_groups2);
b6b28d93 4067 }
46312f7d 4068 $contact_get3 = $this->callAPISuccess('contact', 'get', ['group' => [$createdGroupsIds[0] => 1], 'return' => 'group']);
b6b28d93
SL
4069 $this->assertEquals($created_contact_id, $contact_get3['id']);
4070 $contact_groups3 = explode(',', $contact_get3['values'][$created_contact_id]['groups']);
4071 foreach ($createdGroupsIds as $id) {
62b8c91c 4072 $this->assertContains((string) $id, $contact_groups3);
b6b28d93 4073 }
46312f7d 4074 $contact_get4 = $this->callAPISuccess('contact', 'get', ['group' => [$createdGroupsIds[0] => 1, $createdGroupsIds[1] => 1], 'return' => 'group']);
b6b28d93 4075 $this->assertEquals($created_contact_id, $contact_get4['id']);
62b8c91c 4076 $contact_groups4 = explode(',', $contact_get4['values'][$created_contact_id]['groups']);
b6b28d93 4077 foreach ($createdGroupsIds as $id) {
62b8c91c 4078 $this->assertContains((string) $id, $contact_groups4);
b6b28d93
SL
4079 }
4080 foreach ($createdGroupsIds as $id) {
46312f7d 4081 $this->callAPISuccess('group', 'delete', ['id' => $id]);
b6b28d93 4082 }
46312f7d 4083 $this->callAPISuccess('contact', 'delete', ['id' => $created_contact_id, 'skip_undelete' => TRUE]);
b6b28d93
SL
4084 }
4085
4b2d36d7 4086 /**
4087 * Test the prox_distance functionality works.
4088 *
4089 * This is primarily testing functionality in the BAO_Query object that 'happens to be'
4090 * accessible via the api.
4091 */
4092 public function testContactGetProximity() {
4093 CRM_Core_Config::singleton()->geocodeMethod = 'CRM_Utils_MockGeocoder';
4094 $this->individualCreate();
4095 $contactID = $this->individualCreate();
4096 $this->callAPISuccess('Address', 'create', [
4097 'contact_id' => $contactID,
4098 'is_primary' => 1,
4099 'city' => 'Whangarei',
4100 'street_address' => 'Dent St',
4101 'geo_code_1' => '-35.8743325',
4102 'geo_code_2' => '174.4567136',
4103 'location_type_id' => 'Home',
4104 ]);
4105 $contact = $this->callAPISuccess('Contact', 'get', [
4106 'prox_distance' => 100,
4107 'prox_geo_code_1' => '-35.72192',
4108 'prox_geo_code_2' => '174.32034',
4109 ]);
4110 $this->assertEquals(1, $contact['count']);
4111 $this->assertEquals($contactID, $contact['id']);
4112 }
4113
83d02301
SL
4114 public function testLoggedInUserAPISupportToken() {
4115 $description = "Get contact id of the current logged in user";
4116 $subFile = "ContactIDOfLoggedInUserContactAPI";
4117 $cid = $this->createLoggedInUser();
46312f7d 4118 $contact = $this->callAPIAndDocument('contact', 'get', ['id' => 'user_contact_id'], __FUNCTION__, __FILE__, $description, $subFile);
83d02301
SL
4119 $this->assertEquals($cid, $contact['id']);
4120 }
4121
ec52a65a 4122 /**
4123 * @param $groupID
4124 * @param $contact
4125 */
4126 protected function putGroupContactCacheInClearableState($groupID, $contact) {
bb2d2335 4127 // We need to force the situation where there is invalid data in the cache and it
ec52a65a 4128 // is due to be cleared.
4129 CRM_Core_DAO::executeQuery("
4130 INSERT INTO civicrm_group_contact_cache (group_id, contact_id)
4131 VALUES ({$groupID}, {$contact['id']})
4132 ");
4133 CRM_Core_DAO::executeQuery("UPDATE civicrm_group SET cache_date = '2017-01-01'");
4134 // Reset so it does not skip.
4135 Civi::$statics['CRM_Contact_BAO_GroupContactCache']['is_refresh_init'] = FALSE;
4136 }
4137
5b1c3fee
VV
4138 /**
4139 * CRM-21041 Test if 'communication style' is set to site default if not passed.
46312f7d 4140 *
2d932085 4141 * @param int $version
46312f7d 4142 *
2d932085 4143 * @dataProvider versionThreeAndFour
46312f7d 4144 * @throws \CRM_Core_Exception
5b1c3fee 4145 */
2d932085
CW
4146 public function testCreateCommunicationStyleUnset($version) {
4147 $this->_apiversion = $version;
46312f7d 4148 $this->callAPISuccess('Contact', 'create', [
5b1c3fee
VV
4149 'first_name' => 'John',
4150 'last_name' => 'Doe',
39b959db 4151 'contact_type' => 'Individual',
46312f7d 4152 ]);
4153 $result = $this->callAPISuccessGetSingle('Contact', ['last_name' => 'Doe']);
5b1c3fee
VV
4154 $this->assertEquals(1, $result['communication_style_id']);
4155 }
459d57b3 4156
5b1c3fee
VV
4157 /**
4158 * CRM-21041 Test if 'communication style' is set if value is passed.
46312f7d 4159 *
4160 * @throws \CRM_Core_Exception
4161 * @throws \CiviCRM_API3_Exception
5b1c3fee
VV
4162 */
4163 public function testCreateCommunicationStylePassed() {
46312f7d 4164 $this->callAPISuccess('Contact', 'create', [
5b1c3fee
VV
4165 'first_name' => 'John',
4166 'last_name' => 'Doe',
4167 'contact_type' => 'Individual',
4168 'communication_style_id' => 'Familiar',
46312f7d 4169 ]);
4170 $result = $this->callAPISuccessGetSingle('Contact', ['last_name' => 'Doe']);
4171 $params = [
5b1c3fee
VV
4172 'option_group_id' => 'communication_style',
4173 'label' => 'Familiar',
4174 'return' => 'value',
46312f7d 4175 ];
5b1c3fee
VV
4176 $optionResult = civicrm_api3('OptionValue', 'get', $params);
4177 $communicationStyle = reset($optionResult['values']);
4178 $this->assertEquals($communicationStyle['value'], $result['communication_style_id']);
4179 }
4180
0db8cd85 4181 /**
4182 * Test that creating a contact with various contact greetings works.
2d932085 4183 * V3 Only.
0db8cd85 4184 */
4185 public function testContactGreetingsCreate() {
46312f7d 4186 $contact = $this->callAPISuccess('Contact', 'create', ['first_name' => 'Alan', 'last_name' => 'MouseMouse', 'contact_type' => 'Individual']);
4187 $contact = $this->callAPISuccessGetSingle('Contact', ['id' => $contact['id'], 'return' => 'postal_greeting']);
0db8cd85 4188 $this->assertEquals('Dear Alan', $contact['postal_greeting_display']);
4189
46312f7d 4190 $contact = $this->callAPISuccess('Contact', 'create', ['id' => $contact['id'], 'postal_greeting_id' => 2]);
4191 $contact = $this->callAPISuccessGetSingle('Contact', ['id' => $contact['id'], 'return' => 'postal_greeting']);
0db8cd85 4192 $this->assertEquals('Dear Alan MouseMouse', $contact['postal_greeting_display']);
4193
46312f7d 4194 $contact = $this->callAPISuccess('Contact', 'create', ['organization_name' => 'Alan\'s Show', 'contact_type' => 'Organization']);
4195 $contact = $this->callAPISuccessGetSingle('Contact', ['id' => $contact['id'], 'return' => 'postal_greeting, addressee, email_greeting']);
0db8cd85 4196 $this->assertEquals('', $contact['postal_greeting_display']);
4197 $this->assertEquals('', $contact['email_greeting_display']);
4198 $this->assertEquals('Alan\'s Show', $contact['addressee_display']);
4199 }
4200
7c990617 4201 /**
4202 * Test that creating a contact with various contact greetings works.
4203 */
4204 public function testContactGreetingsCreateWithCustomField() {
4205 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
46312f7d 4206 $contact = $this->callAPISuccess('Contact', 'create', ['first_name' => 'Alan', 'contact_type' => 'Individual', 'custom_' . $ids['custom_field_id'] => 'Mice']);
7c990617 4207
4208 // Change postal greeting to involve a custom field.
46312f7d 4209 $postalOption = $this->callAPISuccessGetSingle('OptionValue', ['option_group_id' => 'postal_greeting', 'filter' => 1, 'is_default' => 1]);
4210 $this->callAPISuccess('OptionValue', 'create', [
7c990617 4211 'id' => $postalOption['id'],
4212 'name' => 'Dear {contact.first_name} {contact.custom_' . $ids['custom_field_id'] . '}',
4213 'label' => 'Dear {contact.first_name} {contact.custom_' . $ids['custom_field_id'] . '}',
46312f7d 4214 ]);
7c990617 4215
4216 // Update contact & see if postal greeting now reflects the new string.
46312f7d 4217 $this->callAPISuccess('Contact', 'create', ['id' => $contact['id'], 'last_name' => 'MouseyMousey']);
4218 $contact = $this->callAPISuccessGetSingle('Contact', ['id' => $contact['id'], 'return' => 'postal_greeting']);
7c990617 4219 $this->assertEquals('Dear Alan Mice', $contact['postal_greeting_display']);
4220
57369d23 4221 // Set contact to have no postal greeting & check it is correct.
46312f7d 4222 $this->callAPISuccess('Contact', 'create', ['id' => $contact['id'], 'postal_greeting_id' => 'null']);
4223 $contact = $this->callAPISuccessGetSingle('Contact', ['id' => $contact['id'], 'return' => 'postal_greeting']);
57369d23 4224 $this->assertEquals('', $contact['postal_greeting_display']);
4225
7c990617 4226 //Cleanup
46312f7d 4227 $this->callAPISuccess('OptionValue', 'create', ['id' => $postalOption['id'], 'name' => 'Dear {contact.first_name}']);
7c990617 4228 $this->customFieldDelete($ids['custom_field_id']);
4229 $this->customGroupDelete($ids['custom_group_id']);
4230 }
4231
1af690c4 4232 /**
4233 * Test getunique api call for Contact entity
4234 */
4235 public function testContactGetUnique() {
46312f7d 4236 $result = $this->callAPIAndDocument($this->_entity, 'getunique', [], __FUNCTION__, __FILE__);
1af690c4 4237 $this->assertEquals(1, $result['count']);
46312f7d 4238 $this->assertEquals(['external_identifier'], $result['values']['UI_external_identifier']);
1af690c4 4239 }
4240
3c8e2962
PN
4241 /**
4242 * API test to retrieve contact from group having different group title and name.
4243 */
4244 public function testContactGetFromGroup() {
4245 $groupId = $this->groupCreate([
4246 'name' => 'Test_Group',
4247 'domain_id' => 1,
4248 'title' => 'New Test Group Created',
4249 'description' => 'New Test Group Created',
4250 'is_active' => 1,
4251 'visibility' => 'User and User Admin Only',
4252 ]);
4253 $contact = $this->callAPISuccess('contact', 'create', $this->_params);
46312f7d 4254 $groupContactCreateParams = [
3c8e2962
PN
4255 'contact_id' => $contact['id'],
4256 'group_id' => $groupId,
4257 'status' => 'Pending',
46312f7d 4258 ];
3c8e2962
PN
4259 $groupContact = $this->callAPISuccess('groupContact', 'create', $groupContactCreateParams);
4260 $groupGetContact = $this->CallAPISuccess('groupContact', 'get', $groupContactCreateParams);
4261 $this->CallAPISuccess('Contact', 'getcount', [
4262 'group' => "Test_Group",
4263 ]);
4264 }
4265
def88c52 4266 /**
4267 * Test the related contacts filter.
4268 *
4269 * @throws \Exception
4270 */
2bedfb3f 4271 public function testSmartGroupsForRelatedContacts() {
46312f7d 4272 $rtype1 = $this->callAPISuccess('relationship_type', 'create', [
2bedfb3f
HA
4273 "name_a_b" => uniqid() . " Child of",
4274 "name_b_a" => uniqid() . " Parent of",
46312f7d 4275 ]);
4276 $rtype2 = $this->callAPISuccess('relationship_type', 'create', [
2bedfb3f
HA
4277 "name_a_b" => uniqid() . " Household Member of",
4278 "name_b_a" => uniqid() . " Household Member is",
46312f7d 4279 ]);
2bedfb3f 4280 $h1 = $this->householdCreate();
46312f7d 4281 $c1 = $this->individualCreate(['last_name' => 'Adams']);
4282 $c2 = $this->individualCreate(['last_name' => 'Adams']);
4283 $this->callAPISuccess('relationship', 'create', [
2bedfb3f
HA
4284 'contact_id_a' => $c1,
4285 'contact_id_b' => $c2,
4286 'is_active' => 1,
39b959db
SL
4287 // Child of
4288 'relationship_type_id' => $rtype1['id'],
46312f7d 4289 ]);
4290 $this->callAPISuccess('relationship', 'create', [
2bedfb3f
HA
4291 'contact_id_a' => $c1,
4292 'contact_id_b' => $h1,
4293 'is_active' => 1,
39b959db
SL
4294 // Household Member of
4295 'relationship_type_id' => $rtype2['id'],
46312f7d 4296 ]);
4297 $this->callAPISuccess('relationship', 'create', [
2bedfb3f
HA
4298 'contact_id_a' => $c2,
4299 'contact_id_b' => $h1,
4300 'is_active' => 1,
39b959db
SL
4301 // Household Member of
4302 'relationship_type_id' => $rtype2['id'],
46312f7d 4303 ]);
2bedfb3f 4304
46312f7d 4305 $ssParams = [
4306 'formValues' => [
39b959db
SL
4307 // Child of
4308 'display_relationship_type' => $rtype1['id'] . '_a_b',
2bedfb3f 4309 'sort_name' => 'Adams',
46312f7d 4310 ],
4311 ];
4312 $g1ID = $this->smartGroupCreate($ssParams, ['name' => uniqid(), 'title' => uniqid()]);
4313 $ssParams = [
4314 'formValues' => [
39b959db
SL
4315 // Household Member of
4316 'display_relationship_type' => $rtype2['id'] . '_a_b',
46312f7d 4317 ],
4318 ];
4319 $g2ID = $this->smartGroupCreate($ssParams, ['name' => uniqid(), 'title' => uniqid()]);
4320 $ssParams = [
4321 'formValues' => [
39b959db
SL
4322 // Household Member is
4323 'display_relationship_type' => $rtype2['id'] . '_b_a',
46312f7d 4324 ],
4325 ];
68f8975b 4326 // the reverse of g2 which adds another layer for overlap at related contact filter
46312f7d 4327 $g3ID = $this->smartGroupCreate($ssParams, ['name' => uniqid(), 'title' => uniqid()]);
2bedfb3f 4328 CRM_Contact_BAO_GroupContactCache::loadAll();
46312f7d 4329 $g1Contacts = $this->callAPISuccess('contact', 'get', ['group' => $g1ID]);
4330 $g2Contacts = $this->callAPISuccess('contact', 'get', ['group' => $g2ID]);
4331 $g3Contacts = $this->callAPISuccess('contact', 'get', ['group' => $g3ID]);
2bedfb3f
HA
4332 $this->assertTrue($g1Contacts['count'] == 1);
4333 $this->assertTrue($g2Contacts['count'] == 2);
68f8975b 4334 $this->assertTrue($g3Contacts['count'] == 1);
2bedfb3f
HA
4335 }
4336
9e4f43aa
SL
4337 /**
4338 * Test creating a note from the contact.create API call when only passing the note as a string.
4339 */
4340 public function testCreateNoteinCreate() {
4341 $loggedInContactID = $this->createLoggedInUser();
4342 $this->_params['note'] = "Test note created by API Call as a String";
4343 $contact = $this->callAPISuccess('Contact', 'create', $this->_params);
4344 $note = $this->callAPISuccess('Note', 'get', ['contact_id' => $loggedInContactID]);
4345 $this->assertEquals($note['values'][$note['id']]['note'], "Test note created by API Call as a String");
4346 $note = $this->callAPISuccess('Note', 'get', ['entity_id' => $contact['id']]);
4347 $this->assertEquals($note['values'][$note['id']]['note'], "Test note created by API Call as a String");
4348 $this->callAPISuccess('Contact', 'delete', ['id' => $contact['id'], 'skip_undelete' => TRUE]);
4349 }
4350
4351 /**
4352 * Test Creating a note from the contact.create api call when passing the note params as an array.
4353 */
4354 public function testCreateNoteinCreateArrayFormat() {
46312f7d 4355 $contact1 = $this->callAPISuccess('Contact', 'create', ['first_name' => 'Alan', 'last_name' => 'MouseMouse', 'contact_type' => 'Individual']);
9e4f43aa
SL
4356 $this->_params['note'] = [['note' => "Test note created by API Call as array", 'contact_id' => $contact1['id']]];
4357 $contact2 = $this->callAPISuccess('Contact', 'create', $this->_params);
4358 $note = $this->callAPISuccess('Note', 'get', ['contact_id' => $contact1['id']]);
4359 $this->assertEquals($note['values'][$note['id']]['note'], "Test note created by API Call as array");
4360 $note = $this->callAPISuccess('Note', 'get', ['entity_id' => $contact2['id']]);
4361 $this->assertEquals($note['values'][$note['id']]['note'], "Test note created by API Call as array");
4362 }
4363
0cf0a3f3
PF
4364 /**
4365 * Verify that passing tag IDs to Contact.get works
4366 *
4367 * Tests the following formats
4368 * - Contact.get tag='id1'
4369 * - Contact.get tag='id1,id2'
4370 * - Contact.get tag='id1, id2'
4371 */
4372 public function testContactGetWithTag() {
4373 $contact = $this->callApiSuccess('Contact', 'create', [
4374 'contact_type' => 'Individual',
4375 'first_name' => 'Test',
4376 'last_name' => 'Tagged',
4377 'email' => 'test@example.org',
4378 ]);
4379 $tags = [];
4380 foreach (['Tag A', 'Tag B'] as $name) {
4381 $tags[] = $this->callApiSuccess('Tag', 'create', [
39b959db 4382 'name' => $name,
0cf0a3f3
PF
4383 ]);
4384 }
4385
4386 // assign contact to "Tag B"
4387 $this->callApiSuccess('EntityTag', 'create', [
4388 'entity_table' => 'civicrm_contact',
4389 'entity_id' => $contact['id'],
4390 'tag_id' => $tags[1]['id'],
4391 ]);
4392
4393 // test format Contact.get tag='id1'
4394 $contact_get = $this->callAPISuccess('Contact', 'get', [
4395 'tag' => $tags[1]['id'],
4396 'return' => 'tag',
4397 ]);
4398 $this->assertEquals(1, $contact_get['count']);
4399 $this->assertEquals($contact['id'], $contact_get['id']);
4400 $this->assertEquals('Tag B', $contact_get['values'][$contact['id']]['tags']);
4401
4402 // test format Contact.get tag='id1,id2'
4403 $contact_get = $this->callAPISuccess('Contact', 'get', [
4404 'tag' => $tags[0]['id'] . ',' . $tags[1]['id'],
4405 'return' => 'tag',
4406 ]);
4407 $this->assertEquals(1, $contact_get['count']);
4408 $this->assertEquals($contact['id'], $contact_get['id']);
4409 $this->assertEquals('Tag B', $contact_get['values'][$contact['id']]['tags']);
4410
4411 // test format Contact.get tag='id1, id2'
4412 $contact_get = $this->callAPISuccess('Contact', 'get', [
4413 'tag' => $tags[0]['id'] . ', ' . $tags[1]['id'],
4414 'return' => 'tag',
4415 ]);
4416 $this->assertEquals(1, $contact_get['count']);
4417 $this->assertEquals($contact['id'], $contact_get['id']);
4418 $this->assertEquals('Tag B', $contact_get['values'][$contact['id']]['tags']);
4419
4420 foreach ($tags as $tag) {
4421 $this->callAPISuccess('Tag', 'delete', ['id' => $tag['id']]);
4422 }
4423 $this->callAPISuccess('Contact', 'delete', [
4424 'id' => $contact['id'],
39b959db 4425 'skip_undelete' => TRUE,
0cf0a3f3
PF
4426 ]);
4427 }
4428
6a488035 4429}