3 +--------------------------------------------------------------------+
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
29 * Test APIv3 civicrm_activity_* functions
31 * @package CiviCRM_APIv3
32 * @subpackage API_Contact
36 * Class api_v3_AddressTest
39 class api_v3_AddressTest
extends CiviUnitTestCase
{
40 protected $_contactID;
41 protected $_locationType;
46 public function setUp() {
47 $this->_entity
= 'Address';
50 $this->_contactID
= $this->organizationCreate();
51 $this->_locationType
= $this->locationTypeCreate();
52 CRM_Core_PseudoConstant
::flush();
54 $this->_params
= array(
55 'contact_id' => $this->_contactID
,
56 'location_type_id' => $this->_locationType
->id
,
57 'street_name' => 'Ambachtstraat',
58 'street_number' => '23',
59 'street_address' => 'Ambachtstraat 23',
60 'postal_code' => '6971 BN',
61 'country_id' => '1152',
67 public function tearDown() {
68 $this->locationTypeDelete($this->_locationType
->id
);
69 $this->contactDelete($this->_contactID
);
70 $this->quickCleanup(array('civicrm_address', 'civicrm_relationship'));
75 * @dataProvider versionThreeAndFour
77 public function testCreateAddress($version) {
78 $this->_apiversion
= $version;
79 $result = $this->callAPIAndDocument('address', 'create', $this->_params
, __FUNCTION__
, __FILE__
);
80 $this->assertEquals(1, $result['count']);
81 $this->assertNotNull($result['values'][$result['id']]['id']);
82 $this->getAndCheck($this->_params
, $result['id'], 'address');
87 * @dataProvider versionThreeAndFour
89 public function testCreateAddressParsing($version) {
90 $this->_apiversion
= $version;
92 'street_parsing' => 1,
93 'street_address' => '54A Excelsior Ave. Apt 1C',
94 'location_type_id' => $this->_locationType
->id
,
95 'contact_id' => $this->_contactID
,
97 $subfile = "AddressParse";
98 $description = "Demonstrates Use of address parsing param.";
99 $result = $this->callAPIAndDocument('address', 'create', $params, __FUNCTION__
, __FILE__
, $description, $subfile);
100 $this->assertEquals(54, $result['values'][$result['id']]['street_number']);
101 $this->assertEquals('A', $result['values'][$result['id']]['street_number_suffix']);
102 $this->assertEquals('Excelsior Ave.', $result['values'][$result['id']]['street_name']);
103 $this->assertEquals('Apt 1C', $result['values'][$result['id']]['street_unit']);
104 $this->callAPISuccess('address', 'delete', array('id' => $result['id']));
109 * Is_primary should be set as a default.
110 * @param int $version
111 * @dataProvider versionThreeAndFour
113 public function testCreateAddressTestDefaults($version) {
114 $this->_apiversion
= $version;
115 $params = $this->_params
;
116 unset($params['is_primary']);
117 $result = $this->callAPISuccess('address', 'create', $params);
118 $this->assertEquals(1, $result['count']);
119 $this->assertEquals(1, $result['values'][$result['id']]['is_primary']);
120 $this->getAndCheck($this->_params
, $result['id'], 'address');
126 public function testCreateAddressTooLongSuffix() {
127 $params = $this->_params
;
128 $params['street_number_suffix'] = 'really long string';
129 $this->callAPIFailure('address', 'create', $params);
133 * Create an address with a master ID and ensure that a relationship is created.
134 * @param int $version
135 * @dataProvider versionThreeAndFour
137 public function testCreateAddressWithMasterRelationshipHousehold($version) {
138 $this->_apiversion
= $version;
139 $householdID = $this->householdCreate();
140 $address = $this->callAPISuccess('address', 'create', array_merge($this->_params
, $this->_params
, array('contact_id' => $householdID)));
141 $individualID = $this->individualCreate();
142 $individualParams = array(
143 'contact_id' => $individualID,
144 'master_id' => $address['id'],
146 $this->callAPISuccess('address', 'create', array_merge($this->_params
, $individualParams));
147 $this->callAPISuccess('relationship', 'getcount', array(
148 'contact_id_a' => $individualID,
149 'contact_id_b' => $this->_contactID
,
154 * Create an address with a master ID and ensure that a relationship is created.
155 * @param int $version
156 * @dataProvider versionThreeAndFour
158 public function testCreateAddressWithMasterRelationshipOrganization($version) {
159 $this->_apiversion
= $version;
160 $address = $this->callAPISuccess('address', 'create', $this->_params
);
161 $individualID = $this->individualCreate();
162 $individualParams = array(
163 'contact_id' => $individualID,
164 'master_id' => $address['id'],
166 $this->callAPISuccess('address', 'create', array_merge($this->_params
, $individualParams));
167 $this->callAPISuccess('relationship', 'getcount', array(
168 'contact_id_a' => $individualID,
169 'contact_id_b' => $this->_contactID
,
174 * Create an address with a master ID and relationship creation disabled.
175 * @param int $version
176 * @dataProvider versionThreeAndFour
178 public function testCreateAddressWithoutMasterRelationshipOrganization($version) {
179 $this->_apiversion
= $version;
180 $address = $this->callAPISuccess('address', 'create', $this->_params
);
181 $individualID = $this->individualCreate();
182 $individualParams = array(
183 'contact_id' => $individualID,
184 'master_id' => $address['id'],
185 'update_current_employer' => 0,
187 $this->callAPISuccess('address', 'create', array_merge($this->_params
, $individualParams));
188 $this->callAPISuccess('relationship', 'getcount', array(
189 'contact_id_a' => $individualID,
190 'contact_id_b' => $this->_contactID
,
195 * Create an address with a master ID and ensure that a relationship is created.
196 * @param int $version
197 * @dataProvider versionThreeAndFour
199 public function testCreateAddressWithMasterRelationshipChangingOrganization($version) {
200 $this->_apiversion
= $version;
201 $address = $this->callAPISuccess('address', 'create', $this->_params
);
202 $organisation2ID = $this->organizationCreate();
203 $address2 = $this->callAPISuccess('address', 'create', array_merge($this->_params
, array('contact_id' => $organisation2ID)));
204 $individualID = $this->individualCreate();
205 $individualParams = array_merge($this->_params
, array(
206 'contact_id' => $individualID,
207 'master_id' => $address['id'],
209 $individualAddress = $this->callAPISuccess('address', 'create', $individualParams);
210 $individualParams['master_id'] = $address2['id'];
211 $individualParams['id'] = $individualAddress['id'];
212 $this->callAPISuccess('address', 'create', $individualParams);
213 $this->callAPISuccessGetCount('relationship', array('contact_id_a' => $individualID), 2);
214 $this->markTestIncomplete('Remainder of test checks that employer relationship is disabled when new one is created but turns out to be not happening - by design?');
215 $this->callAPISuccessGetCount('relationship', array('contact_id_a' => $individualID, 'is_active' => FALSE), 1);
216 $this->callAPISuccessGetCount('relationship', array(
217 'contact_id_a' => $individualID,
219 'contact_id_b' => $organisation2ID,
225 * Is_primary should be set as a default.
227 * ie. create the address, unset the params & recreate.
228 * is_primary should be 0 before & after the update. ie - having no other address
229 * is_primary is invalid.
230 * @param int $version
231 * @dataProvider versionThreeAndFour
233 public function testCreateAddressTestDefaultWithID($version) {
234 $this->_apiversion
= $version;
235 $params = $this->_params
;
236 $params['is_primary'] = 0;
237 $result = $this->callAPISuccess('address', 'create', $params);
238 unset($params['is_primary']);
239 $params['id'] = $result['id'];
240 $this->callAPISuccess('address', 'create', $params);
241 $result = $this->callAPISuccess('address', 'get', array('contact_id' => $params['contact_id']));
242 $this->assertEquals(1, $result['count']);
243 $this->assertEquals(1, $result['values'][$result['id']]['is_primary']);
244 $this->getAndCheck($params, $result['id'], 'address', __FUNCTION__
);
248 * test address deletion.
249 * @param int $version
250 * @dataProvider versionThreeAndFour
252 public function testDeleteAddress($version) {
253 $this->_apiversion
= $version;
254 //check there are no address to start with
255 $get = $this->callAPISuccess('address', 'get', array(
256 'location_type_id' => $this->_locationType
->id
,
258 $this->assertEquals(0, $get['count'], 'Contact already exists ');
261 $create = $this->callAPISuccess('address', 'create', $this->_params
);
263 $result = $this->callAPIAndDocument('address', 'delete', array('id' => $create['id']), __FUNCTION__
, __FILE__
);
264 $this->assertEquals(1, $result['count']);
265 $get = $this->callAPISuccess('address', 'get', array(
266 'location_type_id' => $this->_locationType
->id
,
268 $this->assertEquals(0, $get['count'], 'Contact not successfully deleted In line ' . __LINE__
);
272 * Test civicrm_address_get - success expected.
273 * @param int $version
274 * @dataProvider versionThreeAndFour
276 public function testGetAddress($version) {
277 $this->_apiversion
= $version;
278 $address = $this->callAPISuccess('address', 'create', $this->_params
);
281 'contact_id' => $this->_contactID
,
282 'street_name' => $address['values'][$address['id']]['street_name'],
284 $result = $this->callAPIAndDocument('Address', 'Get', $params, __FUNCTION__
, __FILE__
);
285 $this->callAPISuccess('Address', 'delete', array('id' => $result['id']));
286 $this->assertEquals($address['values'][$address['id']]['location_type_id'], $result['values'][$address['id']]['location_type_id']);
287 $this->assertEquals($address['values'][$address['id']]['is_primary'], $result['values'][$address['id']]['is_primary']);
288 $this->assertEquals($address['values'][$address['id']]['street_address'], $result['values'][$address['id']]['street_address']);
292 * Test civicrm_address_get - success expected.
293 * @param int $version
294 * @dataProvider versionThreeAndFour
296 public function testGetSingleAddress($version) {
297 $this->_apiversion
= $version;
298 $this->callAPISuccess('address', 'create', $this->_params
);
300 'contact_id' => $this->_contactID
,
302 $address = $this->callAPISuccess('Address', 'getsingle', ($params));
303 $this->assertEquals($address['location_type_id'], $this->_params
['location_type_id']);
304 $this->callAPISuccess('address', 'delete', array('id' => $address['id']));
308 * Test civicrm_address_get with sort option- success expected.
309 * @param int $version
310 * @dataProvider versionThreeAndFour
312 public function testGetAddressSort($version) {
313 $this->_apiversion
= $version;
314 $create = $this->callAPISuccess('address', 'create', $this->_params
);
315 $this->callAPISuccess('address', 'create', array_merge($this->_params
, array('street_address' => 'yzy')));
316 $subfile = "AddressSort";
317 $description = "Demonstrates Use of sort filter.";
320 'sort' => 'street_address DESC',
325 $result = $this->callAPIAndDocument('Address', 'Get', $params, __FUNCTION__
, __FILE__
, $description, $subfile);
326 $this->assertEquals(2, $result['count']);
327 $this->assertEquals('Ambachtstraat 23', $result['values'][1]['street_address']);
328 $this->callAPISuccess('address', 'delete', array('id' => $create['id']));
332 * Test civicrm_address_get with sort option- success expected.
333 * @param int $version
334 * @dataProvider versionThreeAndFour
336 public function testGetAddressLikeSuccess($version) {
337 $this->_apiversion
= $version;
338 $this->callAPISuccess('address', 'create', $this->_params
);
339 $subfile = "AddressLike";
340 $description = "Demonstrates Use of Like.";
342 'street_address' => array('LIKE' => '%mb%'),
345 $result = $this->callAPIAndDocument('Address', 'Get', $params, __FUNCTION__
, __FILE__
, $description, $subfile);
346 $this->assertEquals(1, $result['count']);
347 $this->assertEquals('Ambachtstraat 23', $result['values'][0]['street_address']);
348 $this->callAPISuccess('address', 'delete', array('id' => $result['id']));
352 * Test civicrm_address_get with sort option- success expected.
353 * @param int $version
354 * @dataProvider versionThreeAndFour
356 public function testGetAddressLikeFail($version) {
357 $this->_apiversion
= $version;
358 $create = $this->callAPISuccess('address', 'create', $this->_params
);
360 'street_address' => array('LIKE' => "'%xy%'"),
363 $result = $this->callAPISuccess('Address', 'Get', ($params));
364 $this->assertEquals(0, $result['count']);
365 $this->callAPISuccess('address', 'delete', array('id' => $create['id']));
369 * FIXME: Api4 custom address fields broken?
371 public function testGetWithCustom() {
372 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__
, __FILE__
);
374 $params = $this->_params
;
375 $params['custom_' . $ids['custom_field_id']] = "custom string";
377 $result = $this->callAPISuccess($this->_entity
, 'create', $params);
379 $getParams = array('id' => $result['id'], 'return' => array('custom'));
380 $check = $this->callAPISuccess($this->_entity
, 'get', $getParams);
382 $this->assertEquals("custom string", $check['values'][$check['id']]['custom_' . $ids['custom_field_id']], ' in line ' . __LINE__
);
384 $this->customFieldDelete($ids['custom_field_id']);
385 $this->customGroupDelete($ids['custom_group_id']);
386 $this->callAPISuccess('address', 'delete', array('id' => $result['id']));
390 * @param int $version
391 * @dataProvider versionThreeAndFour
393 public function testCreateAddressPrimaryHandlingChangeToPrimary($version) {
394 $this->_apiversion
= $version;
395 $params = $this->_params
;
396 unset($params['is_primary']);
397 $address1 = $this->callAPISuccess('address', 'create', $params);
398 $this->assertApiSuccess($address1);
399 //now we check & make sure it has been set to primary
400 $check = $this->callAPISuccess('address', 'getcount', array(
402 'id' => $address1['id'],
404 $this->assertEquals(1, $check);
405 $this->callAPISuccess('address', 'delete', array('id' => $address1['id']));
409 * @param int $version
410 * @dataProvider versionThreeAndFour
412 public function testCreateAddressPrimaryHandlingChangeExisting($version) {
413 $this->_apiversion
= $version;
414 $address1 = $this->callAPISuccess('address', 'create', $this->_params
);
415 $this->callAPISuccess('address', 'create', $this->_params
);
416 $check = $this->callAPISuccess('address', 'getcount', array(
418 'contact_id' => $this->_contactID
,
420 $this->assertEquals(1, $check);
421 $this->callAPISuccess('address', 'delete', array('id' => $address1['id']));
425 * Test Creating address of same type alreay ind the database
426 * This is legacy API v3 behaviour and not correct behaviour
427 * however we are too far down the path wiwth v3 to fix this
428 * @link https://chat.civicrm.org/civicrm/pl/zcq3jkg69jdt5g4aqze6bbe9pc
431 public function testCreateDuplicateLocationTypes() {
432 $address1 = $this->callAPISuccess('address', 'create', $this->_params
);
433 $address2 = $this->callAPISuccess('address', 'create', array(
434 'location_type_id' => $this->_locationType
->id
,
435 'street_address' => '1600 Pensilvania Avenue',
436 'city' => 'Washington DC',
439 'contact_id' => $this->_contactID
,
441 $check = $this->callAPISuccess('address', 'getcount', array(
442 'contact_id' => $this->_contactID
,
443 'location_type_id' => $this->_locationType
->id
,
445 $this->assertEquals(2, $check);
446 $this->callAPISuccess('address', 'delete', array('id' => $address1['id']));
447 $this->callAPISuccess('address', 'delete', array('id' => $address2['id']));
450 public function testGetWithJoin() {
451 $cid = $this->individualCreate(array(
452 'api.Address.create' => array(
453 'street_address' => __FUNCTION__
,
454 'location_type_id' => $this->_locationType
->id
,
457 $result = $this->callAPISuccess('address', 'getsingle', array(
458 'check_permissions' => TRUE,
459 'contact_id' => $cid,
460 'street_address' => __FUNCTION__
,
461 'return' => 'contact_id.contact_type',
463 $this->assertEquals('Individual', $result['contact_id.contact_type']);
467 * Test Address create with a state name that at least two countries have, e.g. Maryland, United States vs. Maryland, Liberia
469 * @see https://lab.civicrm.org/dev/core/issues/725
471 public function testCreateAddressStateProvinceIDCorrectForCountry() {
472 $params = $this->_params
;
473 $params['sequential'] = 1;
474 // United States country id
475 $params['country_id'] = '1228';
476 $params['state_province_id'] = 'Maryland';
477 $params['city'] = 'Baltimore';
478 $params['street_address'] = '600 N Charles St.';
479 $params['postal_code'] = '21201';
480 unset($params['street_name']);
481 unset($params['street_number']);
482 $address1 = $this->callAPISuccess('address', 'create', $params);
483 // should find state_province_id of 1019, Maryland, United States ... NOT 3497, Maryland, Liberia
484 $this->assertEquals('1019', $address1['values'][0]['state_province_id']);
486 // Now try it in Liberia
487 $params = $this->_params
;
488 $params['sequential'] = 1;
489 // Liberia country id
490 $params['country_id'] = '1122';
491 $params['state_province_id'] = 'Maryland';
492 $address2 = $this->callAPISuccess('address', 'create', $params);
493 $this->assertEquals('3497', $address2['values'][0]['state_province_id']);
496 public function getSymbolicCountryStateExamples() {
498 // [mixed $inputCountry, mixed $inputState, int $expectCountry, int $expectState]
499 [1228, 1004, 1228, 1004],
500 //['US', 'CA', 1228, 1004],
501 //['US', 'TX', 1228, 1042],
502 ['US', 'California', 1228, 1004],
503 [1228, 'Texas', 1228, 1042],
504 // Don't think these have been supported?
505 // ['United States', 1004, 1228, 1004] ,
506 // ['United States', 'TX', 1228, 1042],
511 * @param mixed $inputCountry
513 * @param mixed $inputState
515 * @param int $expectCountry
516 * @param int $expectState
517 * @dataProvider getSymbolicCountryStateExamples
519 public function testCreateAddressSymbolicCountryAndState($inputCountry, $inputState, $expectCountry, $expectState) {
520 $cid = $this->individualCreate();
521 $r = $this->callAPISuccess('Address', 'create', [
522 'contact_id' => $cid,
523 'location_type_id' => 1,
524 'street_address' => '123 Some St',
525 'city' => 'Hereville',
527 'country_id' => $inputCountry,
529 'state_province_id' => $inputState,
530 'postal_code' => '94100',
532 $created = CRM_Utils_Array
::first($r['values']);
533 $this->assertEquals($expectCountry, $created['country_id']);
534 $this->assertEquals($expectState, $created['state_province_id']);
538 * @param int $version
539 * @dataProvider versionThreeAndFour
541 public function testBuildStateProvinceOptionsWithDodgyProvinceLimit($version) {
542 $this->_apiversion
= $version;
543 $provinceLimit = [1228, "abcd;ef"];
544 $this->callAPISuccess('setting', 'create', [
545 'provinceLimit' => $provinceLimit,
547 $result = $this->callAPIFailure('address', 'getoptions', ['field' => 'state_province_id']);
548 // confirm that we hit our error not a SQLI.
549 $this->assertEquals('Province limit or default country setting is incorrect', $result['error_message']);
550 $this->callAPISuccess('setting', 'create', [
551 'provinceLimit' => [1228],
553 // Now confirm with a correct province setting it works fine
554 $this->callAPISuccess('address', 'getoptions', ['field' => 'state_province_id']);
558 * @param int $version
559 * @dataProvider versionThreeAndFour
561 public function testBuildCountryWithDodgyCountryLimitSetting($version) {
562 $this->_apiversion
= $version;
563 $countryLimit = [1228, "abcd;ef"];
564 $this->callAPISuccess('setting', 'create', [
565 'countryLimit' => $countryLimit,
567 $result = $this->callAPIFailure('address', 'getoptions', ['field' => 'country_id']);
568 // confirm that we hit our error not a SQLI.
569 $this->assertEquals('Available Country setting is incorrect', $result['error_message']);
570 $this->callAPISuccess('setting', 'create', [
571 'countryLimit' => [1228],
573 // Now confirm with a correct province setting it works fine
574 $this->callAPISuccess('address', 'getoptions', ['field' => 'country_id']);
577 public function testBuildCountyWithDodgeStateProvinceFiltering() {
578 $result = $this->callAPIFailure('Address', 'getoptions', [
579 'field' => 'county_id',
580 'state_province_id' => "abcd;ef",
582 $this->assertEquals('Can only accept Integers for state_province_id filtering', $result['error_message']);
583 $goodResult = $this->callAPISuccess('Address', 'getoptions', [
584 'field' => 'county_id',
585 'state_province_id' => 1004,
587 $this->assertEquals('San Francisco', $goodResult['values'][4]);