Merge pull request #15856 from agileware/CIVICRM-1368
[civicrm-core.git] / tests / phpunit / CRM / Core / BAO / AddressTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 * Class CRM_Core_BAO_AddressTest
14 * @group headless
15 */
16 class CRM_Core_BAO_AddressTest extends CiviUnitTestCase {
17
18 public function setUp() {
19 parent::setUp();
20
21 $this->quickCleanup(['civicrm_contact', 'civicrm_address']);
22 }
23
24 /**
25 * Create() method (create and update modes)
26 */
27 public function testCreate() {
28 $contactId = $this->individualCreate();
29
30 $params = [];
31 $params['address']['1'] = [
32 'street_address' => 'Oberoi Garden',
33 'supplemental_address_1' => 'Attn: Accounting',
34 'supplemental_address_2' => 'Powai',
35 'supplemental_address_3' => 'Somewhere',
36 'city' => 'Athens',
37 'postal_code' => '01903',
38 'state_province_id' => '1000',
39 'country_id' => '1228',
40 'geo_code_1' => '18.219023',
41 'geo_code_2' => '-105.00973',
42 'location_type_id' => '1',
43 'is_primary' => '1',
44 'is_billing' => '0',
45 ];
46
47 $params['contact_id'] = $contactId;
48
49 $fixAddress = TRUE;
50
51 CRM_Core_BAO_Address::create($params, $fixAddress, $entity = NULL);
52 $addressId = $this->assertDBNotNull('CRM_Core_DAO_Address', 'Oberoi Garden', 'id', 'street_address',
53 'Database check for created address.'
54 );
55
56 // Now call add() to modify an existing address
57
58 $params = [];
59 $params['address']['1'] = [
60 'id' => $addressId,
61 'street_address' => '120 Terminal Road',
62 'supplemental_address_1' => 'A-wing:3037',
63 'supplemental_address_2' => 'Bandra',
64 'supplemental_address_3' => 'Somewhere',
65 'city' => 'Athens',
66 'postal_code' => '01903',
67 'state_province_id' => '1000',
68 'country_id' => '1228',
69 'geo_code_1' => '18.219023',
70 'geo_code_2' => '-105.00973',
71 'location_type_id' => '1',
72 'is_primary' => '1',
73 'is_billing' => '0',
74 ];
75 $params['contact_id'] = $contactId;
76
77 $block = CRM_Core_BAO_Address::create($params, $fixAddress, $entity = NULL);
78
79 $this->assertDBNotNull('CRM_Core_DAO_Address', $contactId, 'id', 'contact_id',
80 'Database check for updated address by contactId.'
81 );
82 $this->assertDBNotNull('CRM_Core_DAO_Address', '120 Terminal Road', 'id', 'street_address',
83 'Database check for updated address by street_name.'
84 );
85 $this->contactDelete($contactId);
86 }
87
88 /**
89 * Add() method ( )
90 */
91 public function testAdd() {
92 $contactId = $this->individualCreate();
93
94 $fixParams = [
95 'street_address' => 'E 906N Pine Pl W',
96 'supplemental_address_1' => 'Editorial Dept',
97 'supplemental_address_2' => '',
98 'supplemental_address_3' => '',
99 'city' => 'El Paso',
100 'postal_code' => '88575',
101 'postal_code_suffix' => '',
102 'state_province_id' => '1001',
103 'country_id' => '1228',
104 'geo_code_1' => '31.694842',
105 'geo_code_2' => '-106.29998',
106 'location_type_id' => '1',
107 'is_primary' => '1',
108 'is_billing' => '0',
109 'contact_id' => $contactId,
110 ];
111
112 $addAddress = CRM_Core_BAO_Address::add($fixParams, $fixAddress = TRUE);
113
114 $addParams = $this->assertDBNotNull('CRM_Core_DAO_Address', $contactId, 'id', 'contact_id',
115 'Database check for created contact address.'
116 );
117
118 $this->assertEquals($addAddress->street_address, 'E 906N Pine Pl W', 'In line' . __LINE__);
119 $this->assertEquals($addAddress->supplemental_address_1, 'Editorial Dept', 'In line' . __LINE__);
120 $this->assertEquals($addAddress->city, 'El Paso', 'In line' . __LINE__);
121 $this->assertEquals($addAddress->postal_code, '88575', 'In line' . __LINE__);
122 $this->assertEquals($addAddress->geo_code_1, '31.694842', 'In line' . __LINE__);
123 $this->assertEquals($addAddress->geo_code_2, '-106.29998', 'In line' . __LINE__);
124 $this->assertEquals($addAddress->country_id, '1228', 'In line' . __LINE__);
125 $this->contactDelete($contactId);
126 }
127
128 /**
129 * AllAddress() method ( )
130 */
131 public function testallAddress() {
132 $contactId = $this->individualCreate();
133
134 $fixParams = [
135 'street_address' => 'E 906N Pine Pl W',
136 'supplemental_address_1' => 'Editorial Dept',
137 'supplemental_address_2' => '',
138 'supplemental_address_3' => '',
139 'city' => 'El Paso',
140 'postal_code' => '88575',
141 'postal_code_suffix' => '',
142 'state_province_id' => '1001',
143 'country_id' => '1228',
144 'geo_code_1' => '31.694842',
145 'geo_code_2' => '-106.29998',
146 'location_type_id' => '1',
147 'is_primary' => '1',
148 'is_billing' => '0',
149 'contact_id' => $contactId,
150 ];
151
152 CRM_Core_BAO_Address::add($fixParams, $fixAddress = TRUE);
153
154 $addParams = $this->assertDBNotNull('CRM_Core_DAO_Address', $contactId, 'id', 'contact_id',
155 'Database check for created contact address.'
156 );
157 $fixParams = [
158 'street_address' => 'SW 719B Beech Dr NW',
159 'supplemental_address_1' => 'C/o OPDC',
160 'supplemental_address_2' => '',
161 'supplemental_address_3' => '',
162 'city' => 'Neillsville',
163 'postal_code' => '54456',
164 'postal_code_suffix' => '',
165 'state_province_id' => '1001',
166 'country_id' => '1228',
167 'geo_code_1' => '44.553719',
168 'geo_code_2' => '-90.61457',
169 'location_type_id' => '2',
170 'is_primary' => '',
171 'is_billing' => '1',
172 'contact_id' => $contactId,
173 ];
174
175 CRM_Core_BAO_Address::add($fixParams, $fixAddress = TRUE);
176
177 $addParams = $this->assertDBNotNull('CRM_Core_DAO_Address', $contactId, 'id', 'contact_id',
178 'Database check for created contact address.'
179 );
180
181 $allAddress = CRM_Core_BAO_Address::allAddress($contactId);
182
183 $this->assertEquals(count($allAddress), 2, 'Checking number of returned addresses.');
184
185 $this->contactDelete($contactId);
186 }
187
188 /**
189 * AllAddress() method ( ) with null value
190 */
191 public function testnullallAddress() {
192 $contactId = $this->individualCreate();
193
194 $fixParams = [
195 'street_address' => 'E 906N Pine Pl W',
196 'supplemental_address_1' => 'Editorial Dept',
197 'supplemental_address_2' => '',
198 'supplemental_address_3' => '',
199 'city' => 'El Paso',
200 'postal_code' => '88575',
201 'postal_code_suffix' => '',
202 'state_province_id' => '1001',
203 'country_id' => '1228',
204 'geo_code_1' => '31.694842',
205 'geo_code_2' => '-106.29998',
206 'location_type_id' => '1',
207 'is_primary' => '1',
208 'is_billing' => '0',
209 'contact_id' => $contactId,
210 ];
211
212 CRM_Core_BAO_Address::add($fixParams, $fixAddress = TRUE);
213
214 $addParams = $this->assertDBNotNull('CRM_Core_DAO_Address', $contactId, 'id', 'contact_id',
215 'Database check for created contact address.'
216 );
217
218 $contact_Id = NULL;
219
220 $allAddress = CRM_Core_BAO_Address::allAddress($contact_Id);
221
222 $this->assertEquals($allAddress, NULL, 'Checking null for returned addresses.');
223
224 $this->contactDelete($contactId);
225 }
226
227 /**
228 * GetValues() method (get Address fields)
229 */
230 public function testGetValues() {
231 $contactId = $this->individualCreate();
232
233 $params = [];
234 $params['address']['1'] = [
235 'street_address' => 'Oberoi Garden',
236 'supplemental_address_1' => 'Attn: Accounting',
237 'supplemental_address_2' => 'Powai',
238 'supplemental_address_3' => 'Somewhere',
239 'city' => 'Athens',
240 'postal_code' => '01903',
241 'state_province_id' => '1000',
242 'country_id' => '1228',
243 'geo_code_1' => '18.219023',
244 'geo_code_2' => '-105.00973',
245 'location_type_id' => '1',
246 'is_primary' => '1',
247 'is_billing' => '0',
248 ];
249
250 $params['contact_id'] = $contactId;
251
252 $fixAddress = TRUE;
253
254 CRM_Core_BAO_Address::create($params, $fixAddress, $entity = NULL);
255
256 $addressId = $this->assertDBNotNull('CRM_Core_DAO_Address', $contactId, 'id', 'contact_id',
257 'Database check for created address.'
258 );
259
260 $entityBlock = ['contact_id' => $contactId];
261 $address = CRM_Core_BAO_Address::getValues($entityBlock);
262 $this->assertEquals($address[1]['id'], $addressId);
263 $this->assertEquals($address[1]['contact_id'], $contactId);
264 $this->assertEquals($address[1]['street_address'], 'Oberoi Garden');
265 $this->contactDelete($contactId);
266 }
267
268 /**
269 * Enable street address parsing.
270 *
271 * @param string $status
272 *
273 * @throws \CRM_Core_Exception
274 */
275 public function setStreetAddressParsing($status) {
276 $options = $this->callAPISuccess('Setting', 'getoptions', ['field' => 'address_options'])['values'];
277 $address_options = reset($this->callAPISuccess('Setting', 'get', ['return' => 'address_options'])['values'])['address_options'];
278 $parsingOption = array_search('Street Address Parsing', $options, TRUE);
279 $optionKey = array_search($parsingOption, $address_options, FALSE);
280 if ($status && !$optionKey) {
281 $address_options[] = $parsingOption;
282 }
283 if (!$status && $optionKey) {
284 unset($address_options[$optionKey]);
285 }
286 $this->callAPISuccess('Setting', 'create', ['address_options' => $address_options]);
287 }
288
289 /**
290 * ParseStreetAddress if enabled, otherwise, don't.
291 *
292 * @throws \CRM_Core_Exception
293 * @throws \CiviCRM_API3_Exception
294 */
295 public function testParseStreetAddressIfEnabled() {
296 // Turn off address standardization. Parsing should work without it.
297 Civi::settings()->set('address_standardization_provider', NULL);
298
299 // Ensure street parsing happens if enabled.
300 $this->setStreetAddressParsing(TRUE);
301
302 $contactId = $this->individualCreate();
303 $street_address = '54 Excelsior Ave.';
304 $params = [
305 'contact_id' => $contactId,
306 'street_address' => $street_address,
307 'location_type_id' => 1,
308 ];
309
310 $result = civicrm_api3('Address', 'create', $params);
311 $value = array_pop($result['values']);
312 $street_number = CRM_Utils_Array::value('street_number', $value);
313 $this->assertEquals($street_number, '54');
314
315 // Ensure street parsing does not happen if disabled.
316 $this->setStreetAddressParsing(FALSE);
317 $result = civicrm_api3('Address', 'create', $params);
318 $value = array_pop($result['values']);
319 $street_number = CRM_Utils_Array::value('street_number', $value);
320 $this->assertEmpty($street_number);
321
322 }
323
324 /**
325 * ParseStreetAddress() method (get street address parsed)
326 */
327 public function testParseStreetAddress() {
328
329 // valid Street address to be parsed ( without locale )
330 $street_address = "54A Excelsior Ave. Apt 1C";
331 $parsedStreetAddress = CRM_Core_BAO_Address::parseStreetAddress($street_address);
332 $this->assertEquals($parsedStreetAddress['street_name'], 'Excelsior Ave.');
333 $this->assertEquals($parsedStreetAddress['street_unit'], 'Apt 1C');
334 $this->assertEquals($parsedStreetAddress['street_number'], '54');
335 $this->assertEquals($parsedStreetAddress['street_number_suffix'], 'A');
336
337 // Out-of-range street number to be parsed.
338 $street_address = '505050505050 Main St';
339 $parsedStreetAddress = CRM_Core_BAO_Address::parseStreetAddress($street_address);
340 $this->assertEquals($parsedStreetAddress['street_name'], '');
341 $this->assertEquals($parsedStreetAddress['street_unit'], '');
342 $this->assertEquals($parsedStreetAddress['street_number'], '');
343 $this->assertEquals($parsedStreetAddress['street_number_suffix'], '');
344
345 // valid Street address to be parsed ( $locale = 'en_US' )
346 $street_address = "54A Excelsior Ave. Apt 1C";
347 $locale = 'en_US';
348 $parsedStreetAddress = CRM_Core_BAO_Address::parseStreetAddress($street_address, $locale);
349 $this->assertEquals($parsedStreetAddress['street_name'], 'Excelsior Ave.');
350 $this->assertEquals($parsedStreetAddress['street_unit'], 'Apt 1C');
351 $this->assertEquals($parsedStreetAddress['street_number'], '54');
352 $this->assertEquals($parsedStreetAddress['street_number_suffix'], 'A');
353
354 // invalid Street address ( $locale = 'en_US' )
355 $street_address = "West St. Apt 1";
356 $locale = 'en_US';
357 $parsedStreetAddress = CRM_Core_BAO_Address::parseStreetAddress($street_address, $locale);
358 $this->assertEquals($parsedStreetAddress['street_name'], 'West St.');
359 $this->assertEquals($parsedStreetAddress['street_unit'], 'Apt 1');
360 $this->assertNotContains('street_number', $parsedStreetAddress);
361 $this->assertNotContains('street_number_suffix', $parsedStreetAddress);
362
363 // valid Street address to be parsed ( $locale = 'fr_CA' )
364 $street_address = "2-123CA Main St";
365 $locale = 'fr_CA';
366 $parsedStreetAddress = CRM_Core_BAO_Address::parseStreetAddress($street_address, $locale);
367 $this->assertEquals($parsedStreetAddress['street_name'], 'Main St');
368 $this->assertEquals($parsedStreetAddress['street_unit'], '2');
369 $this->assertEquals($parsedStreetAddress['street_number'], '123');
370 $this->assertEquals($parsedStreetAddress['street_number_suffix'], 'CA');
371
372 // invalid Street address ( $locale = 'fr_CA' )
373 $street_address = "123 Main St";
374 $locale = 'fr_CA';
375 $parsedStreetAddress = CRM_Core_BAO_Address::parseStreetAddress($street_address, $locale);
376 $this->assertEquals($parsedStreetAddress['street_name'], 'Main St');
377 $this->assertEquals($parsedStreetAddress['street_number'], '123');
378 $this->assertNotContains('street_unit', $parsedStreetAddress);
379 $this->assertNotContains('street_number_suffix', $parsedStreetAddress);
380 }
381
382 /**
383 * @dataProvider supportedAddressParsingLocales
384 */
385 public function testIsSupportedByAddressParsingReturnTrueForSupportedLocales($locale) {
386 $isSupported = CRM_Core_BAO_Address::isSupportedParsingLocale($locale);
387 $this->assertTrue($isSupported);
388 }
389
390 /**
391 * @dataProvider supportedAddressParsingLocales
392 */
393 public function testIsSupportedByAddressParsingReturnTrueForSupportedDefaultLocales($locale) {
394 CRM_Core_Config::singleton()->lcMessages = $locale;
395 $isSupported = CRM_Core_BAO_Address::isSupportedParsingLocale();
396 $this->assertTrue($isSupported);
397
398 }
399
400 public function supportedAddressParsingLocales() {
401 return [
402 ['en_US'],
403 ['en_CA'],
404 ['fr_CA'],
405 ];
406 }
407
408 /**
409 * @dataProvider sampleOFUnsupportedAddressParsingLocales
410 */
411 public function testIsSupportedByAddressParsingReturnFalseForUnSupportedLocales($locale) {
412 $isNotSupported = CRM_Core_BAO_Address::isSupportedParsingLocale($locale);
413 $this->assertFalse($isNotSupported);
414 }
415
416 /**
417 * @dataProvider sampleOFUnsupportedAddressParsingLocales
418 */
419 public function testIsSupportedByAddressParsingReturnFalseForUnSupportedDefaultLocales($locale) {
420 CRM_Core_Config::singleton()->lcMessages = $locale;
421 $isNotSupported = CRM_Core_BAO_Address::isSupportedParsingLocale();
422 $this->assertFalse($isNotSupported);
423 }
424
425 public function sampleOFUnsupportedAddressParsingLocales() {
426 return [
427 ['en_GB'],
428 ['af_ZA'],
429 ['da_DK'],
430 ];
431 }
432
433 /**
434 * CRM-21214 - Ensure all child addresses are updated correctly - 1.
435 * 1. First, create three contacts: A, B, and C
436 * 2. Create an address for contact A
437 * 3. Use contact A's address for contact B
438 * 4. Use contact B's address for contact C
439 * 5. Change contact A's address
440 * Address of Contact C should reflect contact A's address change
441 * Also, Contact C's address' master_id should be Contact A's address id.
442 */
443 public function testSharedAddressChaining1() {
444 $contactIdA = $this->individualCreate([], 0);
445 $contactIdB = $this->individualCreate([], 1);
446 $contactIdC = $this->individualCreate([], 2);
447
448 $addressParamsA = [
449 'street_address' => '123 Fake St.',
450 'location_type_id' => '1',
451 'is_primary' => '1',
452 'contact_id' => $contactIdA,
453 ];
454 $addAddressA = CRM_Core_BAO_Address::add($addressParamsA, FALSE);
455
456 $addressParamsB = [
457 'street_address' => '123 Fake St.',
458 'location_type_id' => '1',
459 'is_primary' => '1',
460 'master_id' => $addAddressA->id,
461 'contact_id' => $contactIdB,
462 ];
463 $addAddressB = CRM_Core_BAO_Address::add($addressParamsB, FALSE);
464
465 $addressParamsC = [
466 'street_address' => '123 Fake St.',
467 'location_type_id' => '1',
468 'is_primary' => '1',
469 'master_id' => $addAddressB->id,
470 'contact_id' => $contactIdC,
471 ];
472 $addAddressC = CRM_Core_BAO_Address::add($addressParamsC, FALSE);
473
474 $updatedAddressParamsA = [
475 'id' => $addAddressA->id,
476 'street_address' => '1313 New Address Lane',
477 'location_type_id' => '1',
478 'is_primary' => '1',
479 'contact_id' => $contactIdA,
480 ];
481 $updatedAddressA = CRM_Core_BAO_Address::add($updatedAddressParamsA, FALSE);
482
483 // CRM-21214 - Has Address C been updated with Address A's new values?
484 $newAddressC = new CRM_Core_DAO_Address();
485 $newAddressC->id = $addAddressC->id;
486 $newAddressC->find(TRUE);
487 $newAddressC->fetch(TRUE);
488
489 $this->assertEquals($updatedAddressA->street_address, $newAddressC->street_address);
490 $this->assertEquals($updatedAddressA->id, $newAddressC->master_id);
491 }
492
493 /**
494 * CRM-21214 - Ensure all child addresses are updated correctly - 2.
495 * 1. First, create three contacts: A, B, and C
496 * 2. Create an address for contact A and B
497 * 3. Use contact A's address for contact C
498 * 4. Use contact B's address for contact A
499 * 5. Change contact B's address
500 * Address of Contact C should reflect contact B's address change
501 * Also, Contact C's address' master_id should be Contact B's address id.
502 */
503 public function testSharedAddressChaining2() {
504 $contactIdA = $this->individualCreate([], 0);
505 $contactIdB = $this->individualCreate([], 1);
506 $contactIdC = $this->individualCreate([], 2);
507
508 $addressParamsA = [
509 'street_address' => '123 Fake St.',
510 'location_type_id' => '1',
511 'is_primary' => '1',
512 'contact_id' => $contactIdA,
513 ];
514 $addAddressA = CRM_Core_BAO_Address::add($addressParamsA, FALSE);
515
516 $addressParamsB = [
517 'street_address' => '123 Fake St.',
518 'location_type_id' => '1',
519 'is_primary' => '1',
520 'contact_id' => $contactIdB,
521 ];
522 $addAddressB = CRM_Core_BAO_Address::add($addressParamsB, FALSE);
523
524 $addressParamsC = [
525 'street_address' => '123 Fake St.',
526 'location_type_id' => '1',
527 'is_primary' => '1',
528 'master_id' => $addAddressA->id,
529 'contact_id' => $contactIdC,
530 ];
531 $addAddressC = CRM_Core_BAO_Address::add($addressParamsC, FALSE);
532
533 $updatedAddressParamsA = [
534 'id' => $addAddressA->id,
535 'street_address' => '123 Fake St.',
536 'location_type_id' => '1',
537 'is_primary' => '1',
538 'master_id' => $addAddressB->id,
539 'contact_id' => $contactIdA,
540 ];
541 $updatedAddressA = CRM_Core_BAO_Address::add($updatedAddressParamsA, FALSE);
542
543 $updatedAddressParamsB = [
544 'id' => $addAddressB->id,
545 'street_address' => '1313 New Address Lane',
546 'location_type_id' => '1',
547 'is_primary' => '1',
548 'contact_id' => $contactIdB,
549 ];
550 $updatedAddressB = CRM_Core_BAO_Address::add($updatedAddressParamsB, FALSE);
551
552 // CRM-21214 - Has Address C been updated with Address B's new values?
553 $newAddressC = new CRM_Core_DAO_Address();
554 $newAddressC->id = $addAddressC->id;
555 $newAddressC->find(TRUE);
556 $newAddressC->fetch(TRUE);
557
558 $this->assertEquals($updatedAddressB->street_address, $newAddressC->street_address);
559 $this->assertEquals($updatedAddressB->id, $newAddressC->master_id);
560 }
561
562 /**
563 * CRM-21214 - Ensure all child addresses are updated correctly - 3.
564 * 1. First, create a contact: A
565 * 2. Create an address for contact A
566 * 3. Use contact A's address for contact A's address
567 * An error should be given, and master_id should remain the same.
568 */
569 public function testSharedAddressChaining3() {
570 $contactIdA = $this->individualCreate([], 0);
571
572 $addressParamsA = [
573 'street_address' => '123 Fake St.',
574 'location_type_id' => '1',
575 'is_primary' => '1',
576 'contact_id' => $contactIdA,
577 ];
578 $addAddressA = CRM_Core_BAO_Address::add($addressParamsA, FALSE);
579
580 $updatedAddressParamsA = [
581 'id' => $addAddressA->id,
582 'street_address' => '123 Fake St.',
583 'location_type_id' => '1',
584 'is_primary' => '1',
585 'master_id' => $addAddressA->id,
586 'contact_id' => $contactIdA,
587 ];
588 $updatedAddressA = CRM_Core_BAO_Address::add($updatedAddressParamsA, FALSE);
589
590 // CRM-21214 - AdressA shouldn't be master of itself.
591 $this->assertEmpty($updatedAddressA->master_id);
592 }
593
594 }