Merge pull request #14879 from eileenmcnaughton/import_gender_test
[civicrm-core.git] / tests / phpunit / CRM / Contact / Import / Parser / ContactTest.php
CommitLineData
e87ff4ce 1<?php
2/*
3+--------------------------------------------------------------------+
2fe49090 4| CiviCRM version 5 |
e87ff4ce 5+--------------------------------------------------------------------+
6b83d5bd 6| Copyright CiviCRM LLC (c) 2004-2019 |
e87ff4ce 7+--------------------------------------------------------------------+
8| This file is a part of CiviCRM. |
9| |
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. |
13| |
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. |
18| |
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+--------------------------------------------------------------------+
26 */
27
28/**
29 * @file
30 * File for the CRM_Contact_Imports_Parser_ContactTest class.
31 */
32
e87ff4ce 33/**
34 * Test contact import parser.
35 *
36 * @package CiviCRM
acb109b7 37 * @group headless
e87ff4ce 38 */
91f1e690 39class CRM_Contact_Import_Parser_ContactTest extends CiviUnitTestCase {
2ab10f80 40 protected $_tablesToTruncate = ['civicrm_address', 'civicrm_phone', 'civicrm_email'];
e87ff4ce 41
42 /**
43 * Setup function.
44 */
45 public function setUp() {
46 parent::setUp();
47 }
48
755a3281
AP
49 /**
50 * Test that import parser will add contact with employee of relationship.
51 *
52 * @throws \Exception
53 */
54 public function testImportParserWtihEmployeeOfRelationship() {
9099cab3 55 $this->organizationCreate([
755a3281
AP
56 "organization_name" => "Agileware",
57 "legal_name" => "Agileware",
9099cab3
CW
58 ]);
59 $contactImportValues = [
755a3281
AP
60 "first_name" => "Alok",
61 "last_name" => "Patel",
62 "Employee of" => "Agileware",
9099cab3 63 ];
755a3281
AP
64
65 $fields = array_keys($contactImportValues);
66 $values = array_values($contactImportValues);
4d847bab 67 $parser = new CRM_Contact_Import_Parser_Contact($fields, []);
755a3281
AP
68 $parser->_contactType = 'Individual';
69 $parser->init();
70 $this->mapRelationshipFields($fields, $parser->getAllFields());
71
9099cab3 72 $parser = new CRM_Contact_Import_Parser_Contact($fields, [], [], [], [
755a3281
AP
73 NULL,
74 NULL,
75 $fields[2],
9099cab3 76 ], [
755a3281
AP
77 NULL,
78 NULL,
79 "Organization",
9099cab3 80 ], [
755a3281
AP
81 NULL,
82 NULL,
83 "organization_name",
9099cab3 84 ], [], [], [], [], []);
755a3281
AP
85
86 $parser->_contactType = 'Individual';
87 $parser->_onDuplicate = CRM_Import_Parser::DUPLICATE_UPDATE;
88 $parser->init();
89
90 $this->assertEquals(CRM_Import_Parser::VALID, $parser->import(CRM_Import_Parser::DUPLICATE_UPDATE, $values), 'Return code from parser import was not as expected');
9099cab3 91 $this->callAPISuccess("Contact", "get", [
39b959db
SL
92 "first_name" => "Alok",
93 "last_name" => "Patel",
94 "organization_name" => "Agileware",
9099cab3 95 ]);
755a3281
AP
96 }
97
13943a50
JM
98 /**
99 * Test that import parser will not fail when same external_identifier found of deleted contact.
100 *
101 * @throws \Exception
102 */
103 public function testImportParserWtihDeletedContactExternalIdentifier() {
9099cab3 104 $contactId = $this->individualCreate([
13943a50 105 "external_identifier" => "ext-1",
9099cab3 106 ]);
13943a50 107 CRM_Contact_BAO_Contact::deleteContact($contactId);
9099cab3 108 list($originalValues, $result) = $this->setUpBaseContact([
13943a50 109 'external_identifier' => 'ext-1',
9099cab3 110 ]);
13943a50
JM
111 $originalValues['nick_name'] = 'Old Bill';
112 $this->runImport($originalValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID);
113 $originalValues['id'] = $result['id'];
9099cab3 114 $this->assertEquals('ext-1', $this->callAPISuccessGetValue('Contact', ['id' => $result['id'], 'return' => 'external_identifier']));
13943a50
JM
115 $this->callAPISuccessGetSingle('Contact', $originalValues);
116 }
117
e87ff4ce 118 /**
8fd37b20 119 * Test import parser will update based on a rule match.
120 *
121 * In this case the contact has no external identifier.
e87ff4ce 122 *
123 * @throws \Exception
124 */
125 public function testImportParserWithUpdateWithoutExternalIdentifier() {
8fd37b20 126 list($originalValues, $result) = $this->setUpBaseContact();
e87ff4ce 127 $originalValues['nick_name'] = 'Old Bill';
128 $this->runImport($originalValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID);
129 $originalValues['id'] = $result['id'];
9099cab3 130 $this->assertEquals('Old Bill', $this->callAPISuccessGetValue('Contact', ['id' => $result['id'], 'return' => 'nick_name']));
e87ff4ce 131 $this->callAPISuccessGetSingle('Contact', $originalValues);
132 }
133
134 /**
8fd37b20 135 * Test import parser will update contacts with an external identifier.
136 *
137 * This is the basic test where the identifier matches the import parameters.
e87ff4ce 138 *
139 * @throws \Exception
140 */
141 public function testImportParserWithUpdateWithExternalIdentifier() {
9099cab3 142 list($originalValues, $result) = $this->setUpBaseContact(['external_identifier' => 'windows']);
8fd37b20 143
e87ff4ce 144 $this->assertEquals($result['id'], CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', 'windows', 'id', 'external_identifier', TRUE));
145 $this->assertEquals('windows', $result['external_identifier']);
8fd37b20 146
e87ff4ce 147 $originalValues['nick_name'] = 'Old Bill';
148 $this->runImport($originalValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID);
149 $originalValues['id'] = $result['id'];
8fd37b20 150
9099cab3 151 $this->assertEquals('Old Bill', $this->callAPISuccessGetValue('Contact', ['id' => $result['id'], 'return' => 'nick_name']));
e87ff4ce 152 $this->callAPISuccessGetSingle('Contact', $originalValues);
153 }
154
65070890 155 /**
156 * Test import parser will fallback to external identifier.
157 *
158 * In this case no primary match exists (e.g the details are not supplied) so it falls back on external identifier.
159 *
160 * CRM-17275
161 *
162 * @throws \Exception
163 */
164 public function testImportParserWithUpdateWithExternalIdentifierButNoPrimaryMatch() {
12e2ccdc 165 list($originalValues, $result) = $this->setUpBaseContact([
65070890 166 'external_identifier' => 'windows',
167 'email' => NULL,
12e2ccdc 168 ]);
65070890 169
170 $this->assertEquals('windows', $result['external_identifier']);
171
172 $originalValues['nick_name'] = 'Old Bill';
173 $this->runImport($originalValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID);
174 $originalValues['id'] = $result['id'];
175
9099cab3 176 $this->assertEquals('Old Bill', $this->callAPISuccessGetValue('Contact', ['id' => $result['id'], 'return' => 'nick_name']));
65070890 177 $this->callAPISuccessGetSingle('Contact', $originalValues);
178 }
179
12e2ccdc 180 /**
181 * Test import parser will fallback to external identifier.
182 *
183 * In this case no primary match exists (e.g the details are not supplied) so it falls back on external identifier.
184 *
185 * CRM-17275
186 *
187 * @throws \Exception
188 */
189 public function testImportParserWithUpdateWithContactID() {
9099cab3 190 list($originalValues, $result) = $this->setUpBaseContact([
12e2ccdc 191 'external_identifier' => '',
192 'email' => NULL,
9099cab3 193 ]);
12e2ccdc 194 $updateValues = ['id' => $result['id'], 'email' => 'bill@example.com'];
195 // This is some deep weirdness - this sets a flag for updatingBlankLocinfo - allowing input to be blanked
196 // (which IS a good thing but it's pretty weird & all to do with legacy profile stuff).
197 CRM_Core_Session::singleton()->set('authSrc', CRM_Core_Permission::AUTH_SRC_CHECKSUM);
198 $this->runImport($updateValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, [NULL, 1]);
199 $originalValues['id'] = $result['id'];
200 $this->callAPISuccessGetSingle('Email', ['contact_id' => $originalValues['id'], 'is_primary' => 1]);
201 $this->callAPISuccessGetSingle('Contact', $originalValues);
202 }
203
eb5f7260 204 /**
8fd37b20 205 * Test that the import parser adds the external identifier where none is set.
eb5f7260 206 *
207 * @throws \Exception
208 */
8fd37b20 209 public function testImportParserWithUpdateWithNoExternalIdentifier() {
210 list($originalValues, $result) = $this->setUpBaseContact();
eb5f7260 211 $originalValues['nick_name'] = 'Old Bill';
212 $originalValues['external_identifier'] = 'windows';
213 $this->runImport($originalValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID);
214 $originalValues['id'] = $result['id'];
9099cab3 215 $this->assertEquals('Old Bill', $this->callAPISuccessGetValue('Contact', ['id' => $result['id'], 'return' => 'nick_name']));
eb5f7260 216 $this->callAPISuccessGetSingle('Contact', $originalValues);
217 }
218
65070890 219 /**
220 * Test that the import parser changes the external identifier when there is a dedupe match.
221 *
222 * @throws \Exception
223 */
224 public function testImportParserWithUpdateWithChangedExternalIdentifier() {
9099cab3 225 list($contactValues, $result) = $this->setUpBaseContact(['external_identifier' => 'windows']);
65070890 226 $contact_id = $result['id'];
227 $contactValues['nick_name'] = 'Old Bill';
228 $contactValues['external_identifier'] = 'android';
229 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID);
230 $contactValues['id'] = $contact_id;
9099cab3 231 $this->assertEquals('Old Bill', $this->callAPISuccessGetValue('Contact', ['id' => $contact_id, 'return' => 'nick_name']));
65070890 232 $this->callAPISuccessGetSingle('Contact', $contactValues);
233 }
234
10741f35 235 /**
6ebecfea 236 * Test that the import parser adds the address to the right location.
10741f35 237 *
238 * @throws \Exception
239 */
240 public function testImportBillingAddress() {
241 list($contactValues) = $this->setUpBaseContact();
242 $contactValues['nick_name'] = 'Old Bill';
243 $contactValues['external_identifier'] = 'android';
244 $contactValues['street_address'] = 'Big Mansion';
6ebecfea 245 $contactValues['phone'] = '911';
9099cab3
CW
246 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, [0 => NULL, 1 => NULL, 2 => NULL, 3 => NULL, 4 => NULL, 5 => 2, 6 => 2]);
247 $address = $this->callAPISuccessGetSingle('Address', ['street_address' => 'Big Mansion']);
10741f35 248 $this->assertEquals(2, $address['location_type_id']);
249
9099cab3 250 $phone = $this->callAPISuccessGetSingle('Phone', ['phone' => '911']);
6ebecfea 251 $this->assertEquals(2, $phone['location_type_id']);
252
253 $contact = $this->callAPISuccessGetSingle('Contact', $contactValues);
9099cab3 254 $this->callAPISuccess('Contact', 'delete', ['id' => $contact['id']]);
6ebecfea 255 }
256
257 /**
258 * Test that the import parser adds the address to the primary location.
259 *
260 * @throws \Exception
261 */
262 public function testImportPrimaryAddress() {
263 list($contactValues) = $this->setUpBaseContact();
264 $contactValues['nick_name'] = 'Old Bill';
265 $contactValues['external_identifier'] = 'android';
266 $contactValues['street_address'] = 'Big Mansion';
267 $contactValues['phone'] = 12334;
9099cab3
CW
268 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, [0 => NULL, 1 => NULL, 2 => 'Primary', 3 => NULL, 4 => NULL, 5 => 'Primary', 6 => 'Primary']);
269 $address = $this->callAPISuccessGetSingle('Address', ['street_address' => 'Big Mansion']);
6ebecfea 270 $this->assertEquals(1, $address['location_type_id']);
c77e8e33 271 $this->assertEquals(1, $address['is_primary']);
6ebecfea 272
9099cab3 273 $phone = $this->callAPISuccessGetSingle('Phone', ['phone' => '12334']);
6ebecfea 274 $this->assertEquals(1, $phone['location_type_id']);
275
9099cab3 276 $this->callAPISuccessGetSingle('Email', ['email' => 'bill.gates@microsoft.com']);
2ab10f80 277
6ebecfea 278 $contact = $this->callAPISuccessGetSingle('Contact', $contactValues);
9099cab3 279 $this->callAPISuccess('Contact', 'delete', ['id' => $contact['id']]);
6ebecfea 280 }
281
be2db205 282 /**
283 * Test that address custom fields can be imported
2d932085 284 * FIXME: Api4
44134d5c 285 *
286 * @throws \CRM_Core_Exception
be2db205 287 */
288 public function testAddressWithCustomData() {
289 $ids = $this->entityCustomGroupWithSingleFieldCreate('Address', 'AddressTest.php');
290 list($contactValues) = $this->setUpBaseContact();
291 $contactValues['nick_name'] = 'Old Bill';
292 $contactValues['external_identifier'] = 'android';
293 $contactValues['street_address'] = 'Big Mansion';
294 $contactValues['custom_' . $ids['custom_field_id']] = 'Update';
9099cab3 295 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, [0 => NULL, 1 => NULL, 2 => NULL, 3 => NULL, 4 => NULL, 5 => 'Primary', 6 => 'Primary']);
be2db205 296 $address = $this->callAPISuccessGetSingle('Address', ['street_address' => 'Big Mansion', 'return' => 'custom_' . $ids['custom_field_id']]);
297 $this->assertEquals('Update', $address['custom_' . $ids['custom_field_id']]);
298 }
299
44134d5c 300 /**
301 * Test gender works when you specify the label.
302 *
303 * There is an expectation that you can import by label here.
304 *
305 * @throws \CRM_Core_Exception
306 */
307 public function testGenderLabel() {
308 $contactValues = [
309 'first_name' => 'Bill',
310 'last_name' => 'Gates',
311 'email' => 'bill.gates@microsoft.com',
312 'nick_name' => 'Billy-boy',
313 'gender_id' => 'Female',
314 ];
315 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, [NULL, NULL, 'Primary', NULL, NULL]);
316 $this->callAPISuccessGetSingle('Contact', $contactValues);
317 }
318
6fdc0e61 319 /**
320 * Test that the import parser adds the address to the primary location.
321 *
322 * @throws \Exception
323 */
324 public function testImportDeceased() {
325 list($contactValues) = $this->setUpBaseContact();
326 CRM_Core_Session::singleton()->set("dateTypes", 1);
327 $contactValues['birth_date'] = '1910-12-17';
328 $contactValues['deceased_date'] = '2010-12-17';
329 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID);
330 $contact = $this->callAPISuccessGetSingle('Contact', $contactValues);
331 $this->assertEquals('1910-12-17', $contact['birth_date']);
332 $this->assertEquals('2010-12-17', $contact['deceased_date']);
333 $this->assertEquals(1, $contact['is_deceased']);
9099cab3 334 $this->callAPISuccess('Contact', 'delete', ['id' => $contact['id']]);
6fdc0e61 335 }
336
6ebecfea 337 /**
338 * Test that the import parser adds the address to the primary location.
339 *
340 * @throws \Exception
341 */
342 public function testImportTwoAddressFirstPrimary() {
343 list($contactValues) = $this->setUpBaseContact();
344 $contactValues['nick_name'] = 'Old Bill';
345 $contactValues['external_identifier'] = 'android';
346 $contactValues['street_address'] = 'Big Mansion';
347 $contactValues['phone'] = 12334;
348 $fields = array_keys($contactValues);
349 $contactValues['street_address_2'] = 'Teeny Mansion';
350 $contactValues['phone_2'] = 4444;
351 $fields[] = 'street_address';
352 $fields[] = 'phone';
9099cab3
CW
353 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, [0 => NULL, 1 => NULL, 2 => NULL, 3 => NULL, 4 => NULL, 5 => 'Primary', 6 => 'Primary', 7 => 3, 8 => 3], $fields);
354 $contact = $this->callAPISuccessGetSingle('Contact', ['external_identifier' => 'android']);
355 $address = $this->callAPISuccess('Address', 'get', ['contact_id' => $contact['id'], 'sequential' => 1]);
6ebecfea 356
357 $this->assertEquals(3, $address['values'][0]['location_type_id']);
358 $this->assertEquals(0, $address['values'][0]['is_primary']);
359 $this->assertEquals('Teeny Mansion', $address['values'][0]['street_address']);
360
361 $this->assertEquals(1, $address['values'][1]['location_type_id']);
362 $this->assertEquals(1, $address['values'][1]['is_primary']);
363 $this->assertEquals('Big Mansion', $address['values'][1]['street_address']);
364
9099cab3 365 $phone = $this->callAPISuccess('Phone', 'get', ['contact_id' => $contact['id'], 'sequential' => 1]);
6ebecfea 366 $this->assertEquals(1, $phone['values'][0]['location_type_id']);
367 $this->assertEquals(1, $phone['values'][0]['is_primary']);
368 $this->assertEquals(12334, $phone['values'][0]['phone']);
369 $this->assertEquals(3, $phone['values'][1]['location_type_id']);
370 $this->assertEquals(0, $phone['values'][1]['is_primary']);
371 $this->assertEquals(4444, $phone['values'][1]['phone']);
372
9099cab3 373 $this->callAPISuccess('Contact', 'delete', ['id' => $contact['id']]);
6ebecfea 374 }
375
376 /**
377 * Test that the import parser adds the address to the primary location.
378 *
379 * @throws \Exception
380 */
381 public function testImportTwoAddressSecondPrimary() {
382 list($contactValues) = $this->setUpBaseContact();
383 $contactValues['nick_name'] = 'Old Bill';
384 $contactValues['external_identifier'] = 'android';
385 $contactValues['street_address'] = 'Big Mansion';
386 $contactValues['phone'] = 12334;
387 $fields = array_keys($contactValues);
388 $contactValues['street_address_2'] = 'Teeny Mansion';
389 $contactValues['phone_2'] = 4444;
390 $fields[] = 'street_address';
391 $fields[] = 'phone';
9099cab3
CW
392 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, [0 => NULL, 1 => NULL, 2 => NULL, 3 => NULL, 4 => NULL, 5 => 3, 6 => 3, 7 => 'Primary', 8 => 'Primary'], $fields);
393 $contact = $this->callAPISuccessGetSingle('Contact', ['external_identifier' => 'android']);
394 $address = $this->callAPISuccess('Address', 'get', ['contact_id' => $contact['id'], 'sequential' => 1])['values'];
6ebecfea 395
91f1e690 396 $this->assertEquals(1, $address[1]['location_type_id']);
397 $this->assertEquals(1, $address[1]['is_primary']);
398 $this->assertEquals('Teeny Mansion', $address[1]['street_address']);
6ebecfea 399
91f1e690 400 $this->assertEquals(3, $address[0]['location_type_id']);
401 $this->assertEquals(0, $address[0]['is_primary']);
402 $this->assertEquals('Big Mansion', $address[0]['street_address']);
6ebecfea 403
2ab10f80 404 $phone = $this->callAPISuccess('Phone', 'get', ['contact_id' => $contact['id'], 'sequential' => 1, 'options' => ['sort' => 'is_primary DESC']])['values'];
91f1e690 405 $this->assertEquals(3, $phone[1]['location_type_id']);
406 $this->assertEquals(0, $phone[1]['is_primary']);
407 $this->assertEquals(12334, $phone[1]['phone']);
408 $this->assertEquals(1, $phone[0]['location_type_id']);
409 $this->assertEquals(1, $phone[0]['is_primary']);
410 $this->assertEquals(4444, $phone[0]['phone']);
6ebecfea 411
9099cab3 412 $this->callAPISuccess('Contact', 'delete', ['id' => $contact['id']]);
6ebecfea 413 }
414
415 /**
416 * Test that the import parser updates the address on the existing primary location.
417 *
418 * @throws \Exception
419 */
420 public function testImportPrimaryAddressUpdate() {
9099cab3 421 list($contactValues) = $this->setUpBaseContact(['external_identifier' => 'android']);
2ab10f80 422 $contactValues['email'] = 'melinda.gates@microsoft.com';
423 $contactValues['phone'] = '98765';
6ebecfea 424 $contactValues['external_identifier'] = 'android';
425 $contactValues['street_address'] = 'Big Mansion';
c77e8e33 426 $contactValues['city'] = 'Big City';
9099cab3
CW
427 $contactID = $this->callAPISuccessGetValue('Contact', ['external_identifier' => 'android', 'return' => 'id']);
428 $originalAddress = $this->callAPISuccess('Address', 'create', ['location_type_id' => 2, 'street_address' => 'small house', 'contact_id' => $contactID]);
429 $originalPhone = $this->callAPISuccess('phone', 'create', ['location_type_id' => 2, 'phone' => '1234', 'contact_id' => $contactID]);
430 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, [0 => NULL, 1 => NULL, 2 => 'Primary', 3 => NULL, 4 => NULL, 5 => 'Primary', 6 => 'Primary', 7 => 'Primary']);
2ab10f80 431 $phone = $this->callAPISuccessGetSingle('Phone', ['phone' => '98765']);
432 $this->assertEquals(2, $phone['location_type_id']);
433 $this->assertEquals($originalPhone['id'], $phone['id']);
434 $email = $this->callAPISuccess('Email', 'getsingle', ['contact_id' => $contactID]);
9099cab3 435 $address = $this->callAPISuccessGetSingle('Address', ['street_address' => 'Big Mansion']);
6ebecfea 436 $this->assertEquals(2, $address['location_type_id']);
437 $this->assertEquals($originalAddress['id'], $address['id']);
c77e8e33 438 $this->assertEquals('Big City', $address['city']);
10741f35 439 $this->callAPISuccessGetSingle('Contact', $contactValues);
440 }
441
13943a50
JM
442 /**
443 * Test the determination of whether a custom field is valid.
444 */
412585fb 445 public function testCustomFieldValidation() {
9099cab3
CW
446 $errorMessage = [];
447 $customGroup = $this->customGroupCreate([
3b2c326e 448 'extends' => 'Contact',
f1230f06 449 'title' => 'ABC',
9099cab3
CW
450 ]);
451 $customField = $this->customFieldOptionValueCreate($customGroup, 'fieldABC', ['html_type' => 'Multi-Select']);
452 $params = [
412585fb 453 'custom_' . $customField['id'] => 'Label1|Label2',
9099cab3 454 ];
412585fb 455 CRM_Contact_Import_Parser_Contact::isErrorInCustomData($params, $errorMessage);
9099cab3 456 $this->assertEquals([], $errorMessage);
412585fb 457 }
458
6e975197
JM
459 /**
460 * Test that setting duplicate action to fill doesn't blow away data
461 * that exists, but does fill in where it's empty.
462 *
463 * @throw \Exception
464 */
465 public function testImportFill() {
466 // Create a custom field group for testing.
467 $custom_group_name = 'importFillGroup';
9099cab3 468 $results = $this->callAPISuccess('customGroup', 'get', ['title' => $custom_group_name]);
6e975197 469 if ($results['count'] == 0) {
9099cab3 470 $api_params = [
6e975197
JM
471 'title' => $custom_group_name,
472 'extends' => 'Individual',
473 'is_active' => TRUE,
9099cab3 474 ];
6e975197
JM
475 $customGroup = $this->callAPISuccess('customGroup', 'create', $api_params);
476 }
477
478 // Add two custom fields.
9099cab3 479 $api_params = [
6e975197
JM
480 'custom_group_id' => $customGroup['id'],
481 'label' => 'importFillField1',
482 'html_type' => 'Select',
483 'data_type' => 'String',
9099cab3 484 'option_values' => [
6e975197
JM
485 'foo' => 'Foo',
486 'bar' => 'Bar',
9099cab3
CW
487 ],
488 ];
6e975197
JM
489 $result = $this->callAPISuccess('custom_field', 'create', $api_params);
490 $customField1 = $result['id'];
491
9099cab3 492 $api_params = [
6e975197
JM
493 'custom_group_id' => $customGroup['id'],
494 'label' => 'importFillField2',
495 'html_type' => 'Select',
496 'data_type' => 'String',
9099cab3 497 'option_values' => [
6e975197
JM
498 'baz' => 'Baz',
499 'boo' => 'Boo',
9099cab3
CW
500 ],
501 ];
6e975197
JM
502 $result = $this->callAPISuccess('custom_field', 'create', $api_params);
503 $customField2 = $result['id'];
504
505 // Now set up values.
506 $original_gender = 'Male';
507 $original_custom1 = 'foo';
508 $original_job_title = '';
509 $original_custom2 = '';
510 $original_email = 'test-import-fill@example.org';
511
512 $import_gender = 'Female';
513 $import_custom1 = 'bar';
514 $import_job_title = 'Chief data importer';
515 $import_custom2 = 'baz';
516
517 // Create contact with both one known core field and one custom
518 // field filled in.
9099cab3 519 $api_params = [
6e975197
JM
520 'contact_type' => 'Individual',
521 'email' => $original_email,
522 'gender' => $original_gender,
f3cfbe94 523 'custom_' . $customField1 => $original_custom1,
9099cab3 524 ];
6e975197
JM
525 $result = $this->callAPISuccess('contact', 'create', $api_params);
526 $contact_id = $result['id'];
527
528 // Run an import.
9099cab3 529 $import = [
6e975197
JM
530 'email' => $original_email,
531 'gender_id' => $import_gender,
532 'custom_' . $customField1 => $import_custom1,
533 'job_title' => $import_job_title,
f3cfbe94 534 'custom_' . $customField2 => $import_custom2,
9099cab3 535 ];
6e975197
JM
536
537 $this->runImport($import, CRM_Import_Parser::DUPLICATE_FILL, CRM_Import_Parser::VALID);
538
9099cab3 539 $expected = [
6e975197
JM
540 'gender' => $original_gender,
541 'custom_' . $customField1 => $original_custom1,
542 'job_title' => $import_job_title,
f3cfbe94 543 'custom_' . $customField2 => $import_custom2,
9099cab3 544 ];
6e975197 545
9099cab3 546 $params = [
6e975197 547 'id' => $contact_id,
9099cab3 548 'return' => [
6e975197
JM
549 'gender',
550 'custom_' . $customField1,
551 'job_title',
f3cfbe94 552 'custom_' . $customField2,
9099cab3
CW
553 ],
554 ];
6e975197
JM
555 $result = civicrm_api3('Contact', 'get', $params);
556 $values = array_pop($result['values']);
f3cfbe94 557 foreach ($expected as $field => $expected_value) {
6e975197 558 if (!isset($values[$field])) {
f3cfbe94 559 $given_value = NULL;
6e975197
JM
560 }
561 else {
562 $given_value = $values[$field];
563 }
564 // We expect:
565 // gender: Male
566 // job_title: Chief Data Importer
567 // importFillField1: foo
568 // importFillField2: baz
569 $this->assertEquals($expected_value, $given_value, "$field properly handled during Fill import");
570 }
571 }
572
4352bd72 573 /**
574 * CRM-19888 default country should be used if ambigous.
575 */
576 public function testImportAmbiguousStateCountry() {
1c8738dd 577 $this->callAPISuccess('Setting', 'create', ['defaultContactCountry' => 1228]);
4352bd72 578 $countries = CRM_Core_PseudoConstant::country(FALSE, FALSE);
9099cab3
CW
579 $this->callAPISuccess('Setting', 'create', ['countryLimit' => [array_search('United States', $countries), array_search('Guyana', $countries), array_search('Netherlands', $countries)]]);
580 $this->callAPISuccess('Setting', 'create', ['provinceLimit' => [array_search('United States', $countries), array_search('Guyana', $countries), array_search('Netherlands', $countries)]]);
581 $mapper = [0 => NULL, 1 => NULL, 2 => 'Primary', 3 => NULL];
4352bd72 582 list($contactValues) = $this->setUpBaseContact();
583 $fields = array_keys($contactValues);
9099cab3 584 $addressValues = [
4352bd72 585 'street_address' => 'PO Box 2716',
586 'city' => 'Midway',
587 'state_province' => 'UT',
588 'postal_code' => 84049,
589 'country' => 'United States',
9099cab3
CW
590 ];
591 $locationTypes = $this->callAPISuccess('Address', 'getoptions', ['field' => 'location_type_id']);
4352bd72 592 $locationTypes = $locationTypes['values'];
593 foreach ($addressValues as $field => $value) {
594 $contactValues['home_' . $field] = $value;
595 $mapper[] = array_search('Home', $locationTypes);
596 $contactValues['work_' . $field] = $value;
597 $mapper[] = array_search('Work', $locationTypes);
598 $fields[] = $field;
599 $fields[] = $field;
600 }
601 $contactValues['work_country'] = '';
602
603 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, $mapper, $fields);
9099cab3 604 $addresses = $this->callAPISuccess('Address', 'get', ['contact_id' => ['>' => 2], 'sequential' => 1]);
4352bd72 605 $this->assertEquals(2, $addresses['count']);
606 $this->assertEquals(array_search('United States', $countries), $addresses['values'][0]['country_id']);
607 $this->assertEquals(array_search('United States', $countries), $addresses['values'][1]['country_id']);
608 }
609
e87ff4ce 610 /**
611 * Run the import parser.
612 *
613 * @param array $originalValues
614 *
615 * @param int $onDuplicateAction
616 * @param int $expectedResult
10741f35 617 * @param array|null $mapperLocType
91f1e690 618 * Array of location types that map to the input arrays.
6ebecfea 619 * @param array|null $fields
620 * Array of field names. Will be calculated from $originalValues if not passed in, but
621 * that method does not cope with duplicates.
e87ff4ce 622 */
91f1e690 623 protected function runImport($originalValues, $onDuplicateAction, $expectedResult, $mapperLocType = [], $fields = NULL) {
6ebecfea 624 if (!$fields) {
625 $fields = array_keys($originalValues);
626 }
e87ff4ce 627 $values = array_values($originalValues);
10741f35 628 $parser = new CRM_Contact_Import_Parser_Contact($fields, $mapperLocType);
e87ff4ce 629 $parser->_contactType = 'Individual';
630 $parser->_onDuplicate = $onDuplicateAction;
631 $parser->init();
65070890 632 $this->assertEquals($expectedResult, $parser->import($onDuplicateAction, $values), 'Return code from parser import was not as expected');
e87ff4ce 633 }
ffe87781 634
755a3281
AP
635 /**
636 * @param array $fields Array of fields to be imported
637 * @param array $allfields Array of all fields which can be part of import
638 */
639 private function mapRelationshipFields(&$fields, $allfields) {
640 foreach ($allfields as $key => $fieldtocheck) {
641 $elementIndex = array_search($fieldtocheck->_title, $fields);
642 if ($elementIndex !== FALSE) {
643 $fields[$elementIndex] = $key;
644 }
645 }
646 }
647
8fd37b20 648 /**
649 * Set up the underlying contact.
650 *
651 * @param array $params
652 * Optional extra parameters to set.
653 *
654 * @return array
44134d5c 655 * @throws \CRM_Core_Exception
8fd37b20 656 */
9099cab3
CW
657 protected function setUpBaseContact($params = []) {
658 $originalValues = array_merge([
8fd37b20 659 'first_name' => 'Bill',
660 'last_name' => 'Gates',
661 'email' => 'bill.gates@microsoft.com',
662 'nick_name' => 'Billy-boy',
9099cab3 663 ], $params);
8fd37b20 664 $this->runImport($originalValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID);
665 $result = $this->callAPISuccessGetSingle('Contact', $originalValues);
9099cab3 666 return [$originalValues, $result];
8fd37b20 667 }
668
e87ff4ce 669}