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