CRM-16964 - fixing style warnings.
[civicrm-core.git] / tests / phpunit / CRM / Contact / Import / Parser / ContactTest.php
CommitLineData
e87ff4ce 1<?php
2/*
3+--------------------------------------------------------------------+
3435af9a 4| CiviCRM version 4.7 |
e87ff4ce 5+--------------------------------------------------------------------+
15a4309a 6| Copyright CiviCRM LLC (c) 2004-2017 |
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 */
6e975197 39class CRM_Contact_Import_Parser_ContactTest extends CiviUnitTestCase {
e87ff4ce 40 protected $_tablesToTruncate = array();
41
42 /**
43 * Setup function.
44 */
45 public function setUp() {
46 parent::setUp();
47 }
48
49 /**
8fd37b20 50 * Test import parser will update based on a rule match.
51 *
52 * In this case the contact has no external identifier.
e87ff4ce 53 *
54 * @throws \Exception
55 */
56 public function testImportParserWithUpdateWithoutExternalIdentifier() {
8fd37b20 57 list($originalValues, $result) = $this->setUpBaseContact();
e87ff4ce 58 $originalValues['nick_name'] = 'Old Bill';
59 $this->runImport($originalValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID);
60 $originalValues['id'] = $result['id'];
61 $this->assertEquals('Old Bill', $this->callAPISuccessGetValue('Contact', array('id' => $result['id'], 'return' => 'nick_name')));
62 $this->callAPISuccessGetSingle('Contact', $originalValues);
63 }
64
65 /**
8fd37b20 66 * Test import parser will update contacts with an external identifier.
67 *
68 * This is the basic test where the identifier matches the import parameters.
e87ff4ce 69 *
70 * @throws \Exception
71 */
72 public function testImportParserWithUpdateWithExternalIdentifier() {
8fd37b20 73 list($originalValues, $result) = $this->setUpBaseContact(array('external_identifier' => 'windows'));
74
e87ff4ce 75 $this->assertEquals($result['id'], CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', 'windows', 'id', 'external_identifier', TRUE));
76 $this->assertEquals('windows', $result['external_identifier']);
8fd37b20 77
e87ff4ce 78 $originalValues['nick_name'] = 'Old Bill';
79 $this->runImport($originalValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID);
80 $originalValues['id'] = $result['id'];
8fd37b20 81
e87ff4ce 82 $this->assertEquals('Old Bill', $this->callAPISuccessGetValue('Contact', array('id' => $result['id'], 'return' => 'nick_name')));
83 $this->callAPISuccessGetSingle('Contact', $originalValues);
84 }
85
65070890 86 /**
87 * Test import parser will fallback to external identifier.
88 *
89 * In this case no primary match exists (e.g the details are not supplied) so it falls back on external identifier.
90 *
91 * CRM-17275
92 *
93 * @throws \Exception
94 */
95 public function testImportParserWithUpdateWithExternalIdentifierButNoPrimaryMatch() {
96 list($originalValues, $result) = $this->setUpBaseContact(array(
97 'external_identifier' => 'windows',
98 'email' => NULL,
99 ));
100
101 $this->assertEquals('windows', $result['external_identifier']);
102
103 $originalValues['nick_name'] = 'Old Bill';
104 $this->runImport($originalValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID);
105 $originalValues['id'] = $result['id'];
106
107 $this->assertEquals('Old Bill', $this->callAPISuccessGetValue('Contact', array('id' => $result['id'], 'return' => 'nick_name')));
108 $this->callAPISuccessGetSingle('Contact', $originalValues);
109 }
110
eb5f7260 111 /**
8fd37b20 112 * Test that the import parser adds the external identifier where none is set.
eb5f7260 113 *
114 * @throws \Exception
115 */
8fd37b20 116 public function testImportParserWithUpdateWithNoExternalIdentifier() {
117 list($originalValues, $result) = $this->setUpBaseContact();
eb5f7260 118 $originalValues['nick_name'] = 'Old Bill';
119 $originalValues['external_identifier'] = 'windows';
120 $this->runImport($originalValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID);
121 $originalValues['id'] = $result['id'];
122 $this->assertEquals('Old Bill', $this->callAPISuccessGetValue('Contact', array('id' => $result['id'], 'return' => 'nick_name')));
123 $this->callAPISuccessGetSingle('Contact', $originalValues);
124 }
125
65070890 126 /**
127 * Test that the import parser changes the external identifier when there is a dedupe match.
128 *
129 * @throws \Exception
130 */
131 public function testImportParserWithUpdateWithChangedExternalIdentifier() {
132 list($contactValues, $result) = $this->setUpBaseContact(array('external_identifier' => 'windows'));
133 $contact_id = $result['id'];
134 $contactValues['nick_name'] = 'Old Bill';
135 $contactValues['external_identifier'] = 'android';
136 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID);
137 $contactValues['id'] = $contact_id;
138 $this->assertEquals('Old Bill', $this->callAPISuccessGetValue('Contact', array('id' => $contact_id, 'return' => 'nick_name')));
139 $this->callAPISuccessGetSingle('Contact', $contactValues);
140 }
141
10741f35 142 /**
6ebecfea 143 * Test that the import parser adds the address to the right location.
10741f35 144 *
145 * @throws \Exception
146 */
147 public function testImportBillingAddress() {
148 list($contactValues) = $this->setUpBaseContact();
149 $contactValues['nick_name'] = 'Old Bill';
150 $contactValues['external_identifier'] = 'android';
151 $contactValues['street_address'] = 'Big Mansion';
6ebecfea 152 $contactValues['phone'] = '911';
153 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, array(0 => NULL, 1 => NULL, 2 => NULL, 3 => NULL, 4 => NULL, 5 => 2, 6 => 2));
10741f35 154 $address = $this->callAPISuccessGetSingle('Address', array('street_address' => 'Big Mansion'));
155 $this->assertEquals(2, $address['location_type_id']);
156
6ebecfea 157 $phone = $this->callAPISuccessGetSingle('Phone', array('phone' => '911'));
158 $this->assertEquals(2, $phone['location_type_id']);
159
160 $contact = $this->callAPISuccessGetSingle('Contact', $contactValues);
161 $this->callAPISuccess('Contact', 'delete', array('id' => $contact['id']));
162 }
163
164 /**
165 * Test that the import parser adds the address to the primary location.
166 *
167 * @throws \Exception
168 */
169 public function testImportPrimaryAddress() {
170 list($contactValues) = $this->setUpBaseContact();
171 $contactValues['nick_name'] = 'Old Bill';
172 $contactValues['external_identifier'] = 'android';
173 $contactValues['street_address'] = 'Big Mansion';
174 $contactValues['phone'] = 12334;
175 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, array(0 => NULL, 1 => NULL, 2 => NULL, 3 => NULL, 4 => NULL, 5 => 'Primary', 6 => 'Primary'));
176 $address = $this->callAPISuccessGetSingle('Address', array('street_address' => 'Big Mansion'));
177 $this->assertEquals(1, $address['location_type_id']);
c77e8e33 178 $this->assertEquals(1, $address['is_primary']);
6ebecfea 179
180 $phone = $this->callAPISuccessGetSingle('Phone', array('phone' => '12334'));
181 $this->assertEquals(1, $phone['location_type_id']);
182
183 $contact = $this->callAPISuccessGetSingle('Contact', $contactValues);
184 $this->callAPISuccess('Contact', 'delete', array('id' => $contact['id']));
185 }
186
6fdc0e61 187 /**
188 * Test that the import parser adds the address to the primary location.
189 *
190 * @throws \Exception
191 */
192 public function testImportDeceased() {
193 list($contactValues) = $this->setUpBaseContact();
194 CRM_Core_Session::singleton()->set("dateTypes", 1);
195 $contactValues['birth_date'] = '1910-12-17';
196 $contactValues['deceased_date'] = '2010-12-17';
197 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID);
198 $contact = $this->callAPISuccessGetSingle('Contact', $contactValues);
199 $this->assertEquals('1910-12-17', $contact['birth_date']);
200 $this->assertEquals('2010-12-17', $contact['deceased_date']);
201 $this->assertEquals(1, $contact['is_deceased']);
202 $this->callAPISuccess('Contact', 'delete', array('id' => $contact['id']));
203 }
204
205
6ebecfea 206 /**
207 * Test that the import parser adds the address to the primary location.
208 *
209 * @throws \Exception
210 */
211 public function testImportTwoAddressFirstPrimary() {
212 list($contactValues) = $this->setUpBaseContact();
213 $contactValues['nick_name'] = 'Old Bill';
214 $contactValues['external_identifier'] = 'android';
215 $contactValues['street_address'] = 'Big Mansion';
216 $contactValues['phone'] = 12334;
217 $fields = array_keys($contactValues);
218 $contactValues['street_address_2'] = 'Teeny Mansion';
219 $contactValues['phone_2'] = 4444;
220 $fields[] = 'street_address';
221 $fields[] = 'phone';
222 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, array(0 => NULL, 1 => NULL, 2 => NULL, 3 => NULL, 4 => NULL, 5 => 'Primary', 6 => 'Primary', 7 => 3, 8 => 3), $fields);
223 $contact = $this->callAPISuccessGetSingle('Contact', array('external_identifier' => 'android'));
224 $address = $this->callAPISuccess('Address', 'get', array('contact_id' => $contact['id'], 'sequential' => 1));
225
226 $this->assertEquals(3, $address['values'][0]['location_type_id']);
227 $this->assertEquals(0, $address['values'][0]['is_primary']);
228 $this->assertEquals('Teeny Mansion', $address['values'][0]['street_address']);
229
230 $this->assertEquals(1, $address['values'][1]['location_type_id']);
231 $this->assertEquals(1, $address['values'][1]['is_primary']);
232 $this->assertEquals('Big Mansion', $address['values'][1]['street_address']);
233
234 $phone = $this->callAPISuccess('Phone', 'get', array('contact_id' => $contact['id'], 'sequential' => 1));
235 $this->assertEquals(1, $phone['values'][0]['location_type_id']);
236 $this->assertEquals(1, $phone['values'][0]['is_primary']);
237 $this->assertEquals(12334, $phone['values'][0]['phone']);
238 $this->assertEquals(3, $phone['values'][1]['location_type_id']);
239 $this->assertEquals(0, $phone['values'][1]['is_primary']);
240 $this->assertEquals(4444, $phone['values'][1]['phone']);
241
242 $this->callAPISuccess('Contact', 'delete', array('id' => $contact['id']));
243 }
244
245 /**
246 * Test that the import parser adds the address to the primary location.
247 *
248 * @throws \Exception
249 */
250 public function testImportTwoAddressSecondPrimary() {
251 list($contactValues) = $this->setUpBaseContact();
252 $contactValues['nick_name'] = 'Old Bill';
253 $contactValues['external_identifier'] = 'android';
254 $contactValues['street_address'] = 'Big Mansion';
255 $contactValues['phone'] = 12334;
256 $fields = array_keys($contactValues);
257 $contactValues['street_address_2'] = 'Teeny Mansion';
258 $contactValues['phone_2'] = 4444;
259 $fields[] = 'street_address';
260 $fields[] = 'phone';
261 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, array(0 => NULL, 1 => NULL, 2 => NULL, 3 => NULL, 4 => NULL, 5 => 3, 6 => 3, 7 => 'Primary', 8 => 'Primary'), $fields);
262 $contact = $this->callAPISuccessGetSingle('Contact', array('external_identifier' => 'android'));
263 $address = $this->callAPISuccess('Address', 'get', array('contact_id' => $contact['id'], 'sequential' => 1));
264
265 $this->assertEquals(1, $address['values'][0]['location_type_id']);
266 $this->assertEquals(1, $address['values'][0]['is_primary']);
267 $this->assertEquals('Teeny Mansion', $address['values'][0]['street_address']);
268
269 $this->assertEquals(3, $address['values'][1]['location_type_id']);
270 $this->assertEquals(0, $address['values'][1]['is_primary']);
271 $this->assertEquals('Big Mansion', $address['values'][1]['street_address']);
272
273 $phone = $this->callAPISuccess('Phone', 'get', array('contact_id' => $contact['id'], 'sequential' => 1));
274 $this->assertEquals(3, $phone['values'][0]['location_type_id']);
275 $this->assertEquals(0, $phone['values'][0]['is_primary']);
276 $this->assertEquals(12334, $phone['values'][0]['phone']);
277 $this->assertEquals(1, $phone['values'][1]['location_type_id']);
278 $this->assertEquals(1, $phone['values'][1]['is_primary']);
279 $this->assertEquals(4444, $phone['values'][1]['phone']);
280
281 $this->callAPISuccess('Contact', 'delete', array('id' => $contact['id']));
282 }
283
284 /**
285 * Test that the import parser updates the address on the existing primary location.
286 *
287 * @throws \Exception
288 */
289 public function testImportPrimaryAddressUpdate() {
290 list($contactValues) = $this->setUpBaseContact(array('external_identifier' => 'android'));
291 $contactValues['nick_name'] = 'Old Bill';
292 $contactValues['external_identifier'] = 'android';
293 $contactValues['street_address'] = 'Big Mansion';
c77e8e33 294 $contactValues['city'] = 'Big City';
6ebecfea 295 $contactID = $this->callAPISuccessGetValue('Contact', array('external_identifier' => 'android', 'return' => 'id'));
296 $originalAddress = $this->callAPISuccess('Address', 'create', array('location_type_id' => 2, 'street_address' => 'small house', 'contact_id' => $contactID));
c77e8e33 297 $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, array(0 => NULL, 1 => NULL, 2 => NULL, 3 => NULL, 4 => NULL, 5 => 'Primary', 6 => 'Primary'));
6ebecfea 298 $address = $this->callAPISuccessGetSingle('Address', array('street_address' => 'Big Mansion'));
299 $this->assertEquals(2, $address['location_type_id']);
300 $this->assertEquals($originalAddress['id'], $address['id']);
c77e8e33 301 $this->assertEquals('Big City', $address['city']);
10741f35 302 $this->callAPISuccessGetSingle('Contact', $contactValues);
303 }
304
6e975197
JM
305 /**
306 * Test that setting duplicate action to fill doesn't blow away data
307 * that exists, but does fill in where it's empty.
308 *
309 * @throw \Exception
310 */
311 public function testImportFill() {
312 // Create a custom field group for testing.
313 $custom_group_name = 'importFillGroup';
314 $results = $this->callAPISuccess('customGroup', 'get', array('title' => $custom_group_name));
315 if ($results['count'] == 0) {
316 $api_params = array(
317 'title' => $custom_group_name,
318 'extends' => 'Individual',
319 'is_active' => TRUE,
320 );
321 $customGroup = $this->callAPISuccess('customGroup', 'create', $api_params);
322 }
323
324 // Add two custom fields.
325 $api_params = array(
326 'custom_group_id' => $customGroup['id'],
327 'label' => 'importFillField1',
328 'html_type' => 'Select',
329 'data_type' => 'String',
330 'option_values' => array(
331 'foo' => 'Foo',
332 'bar' => 'Bar',
333 ),
334 );
335 $result = $this->callAPISuccess('custom_field', 'create', $api_params);
336 $customField1 = $result['id'];
337
338 $api_params = array(
339 'custom_group_id' => $customGroup['id'],
340 'label' => 'importFillField2',
341 'html_type' => 'Select',
342 'data_type' => 'String',
343 'option_values' => array(
344 'baz' => 'Baz',
345 'boo' => 'Boo',
346 ),
347 );
348 $result = $this->callAPISuccess('custom_field', 'create', $api_params);
349 $customField2 = $result['id'];
350
351 // Now set up values.
352 $original_gender = 'Male';
353 $original_custom1 = 'foo';
354 $original_job_title = '';
355 $original_custom2 = '';
356 $original_email = 'test-import-fill@example.org';
357
358 $import_gender = 'Female';
359 $import_custom1 = 'bar';
360 $import_job_title = 'Chief data importer';
361 $import_custom2 = 'baz';
362
363 // Create contact with both one known core field and one custom
364 // field filled in.
365 $api_params = array(
366 'contact_type' => 'Individual',
367 'email' => $original_email,
368 'gender' => $original_gender,
f3cfbe94 369 'custom_' . $customField1 => $original_custom1,
6e975197
JM
370 );
371 $result = $this->callAPISuccess('contact', 'create', $api_params);
372 $contact_id = $result['id'];
373
374 // Run an import.
375 $import = array(
376 'email' => $original_email,
377 'gender_id' => $import_gender,
378 'custom_' . $customField1 => $import_custom1,
379 'job_title' => $import_job_title,
f3cfbe94 380 'custom_' . $customField2 => $import_custom2,
6e975197
JM
381 );
382
383 $this->runImport($import, CRM_Import_Parser::DUPLICATE_FILL, CRM_Import_Parser::VALID);
384
385 $expected = array(
386 'gender' => $original_gender,
387 'custom_' . $customField1 => $original_custom1,
388 'job_title' => $import_job_title,
f3cfbe94 389 'custom_' . $customField2 => $import_custom2,
6e975197
JM
390 );
391
392 $params = array(
393 'id' => $contact_id,
394 'return' => array(
395 'gender',
396 'custom_' . $customField1,
397 'job_title',
f3cfbe94
JM
398 'custom_' . $customField2,
399 ),
6e975197
JM
400 );
401 $result = civicrm_api3('Contact', 'get', $params);
402 $values = array_pop($result['values']);
f3cfbe94 403 foreach ($expected as $field => $expected_value) {
6e975197 404 if (!isset($values[$field])) {
f3cfbe94 405 $given_value = NULL;
6e975197
JM
406 }
407 else {
408 $given_value = $values[$field];
409 }
410 // We expect:
411 // gender: Male
412 // job_title: Chief Data Importer
413 // importFillField1: foo
414 // importFillField2: baz
415 $this->assertEquals($expected_value, $given_value, "$field properly handled during Fill import");
416 }
417 }
418
e87ff4ce 419 /**
420 * Run the import parser.
421 *
422 * @param array $originalValues
423 *
424 * @param int $onDuplicateAction
425 * @param int $expectedResult
10741f35 426 * @param array|null $mapperLocType
6ebecfea 427 * @param array|null $fields
428 * Array of field names. Will be calculated from $originalValues if not passed in, but
429 * that method does not cope with duplicates.
e87ff4ce 430 */
6ebecfea 431 protected function runImport($originalValues, $onDuplicateAction, $expectedResult, $mapperLocType = NULL, $fields = NULL) {
432 if (!$fields) {
433 $fields = array_keys($originalValues);
434 }
e87ff4ce 435 $values = array_values($originalValues);
10741f35 436 $parser = new CRM_Contact_Import_Parser_Contact($fields, $mapperLocType);
e87ff4ce 437 $parser->_contactType = 'Individual';
438 $parser->_onDuplicate = $onDuplicateAction;
439 $parser->init();
65070890 440 $this->assertEquals($expectedResult, $parser->import($onDuplicateAction, $values), 'Return code from parser import was not as expected');
e87ff4ce 441 }
ffe87781 442
8fd37b20 443 /**
444 * Set up the underlying contact.
445 *
446 * @param array $params
447 * Optional extra parameters to set.
448 *
449 * @return array
450 * @throws \Exception
451 */
452 protected function setUpBaseContact($params = array()) {
453 $originalValues = array_merge(array(
454 'first_name' => 'Bill',
455 'last_name' => 'Gates',
456 'email' => 'bill.gates@microsoft.com',
457 'nick_name' => 'Billy-boy',
458 ), $params);
459 $this->runImport($originalValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID);
460 $result = $this->callAPISuccessGetSingle('Contact', $originalValues);
461 return array($originalValues, $result);
462 }
463
e87ff4ce 464}