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