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