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