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