4 * Class CRM_Core_DAOTest
7 class CRM_Export_BAO_ExportTest
extends CiviUnitTestCase
{
10 * Contact IDs created for testing.
14 protected $contactIDs = [];
17 * Contribution IDs created for testing.
21 protected $contributionIDs = [];
24 * Contribution IDs created for testing.
28 protected $activityIDs = [];
31 * Master Address ID created for testing.
35 protected $masterAddressID;
37 public function tearDown() {
38 $this->quickCleanup(['civicrm_contact', 'civicrm_email', 'civicrm_address', 'civicrm_relationship']);
39 $this->quickCleanUpFinancialEntities();
44 * Basic test to ensure the exportComponents function completes without error.
46 public function testExportComponentsNull() {
47 list($tableName, $sqlColumns) = CRM_Export_BAO_Export
::exportComponents(
54 CRM_Export_Form_Select
::CONTACT_EXPORT
,
61 'suppress_csv_for_testing' => TRUE,
65 // delete the export temp table and component table
66 $sql = "DROP TABLE IF EXISTS {$tableName}";
67 CRM_Core_DAO
::executeQuery($sql);
71 * Basic test to ensure the exportComponents function can export selected fields for contribution.
73 public function testExportComponentsContribution() {
74 $this->setUpContributionExportData();
75 $selectedFields = array(
76 array('Individual', 'first_name'),
77 array('Individual', 'last_name'),
78 array('Contribution', 'receive_date'),
79 array('Contribution', 'contribution_source'),
80 array('Individual', 'street_address', 1),
81 array('Individual', 'city', 1),
82 array('Individual', 'country', 1),
83 array('Individual', 'email', 1),
84 array('Contribution', 'trxn_id'),
87 list($tableName, $sqlColumns) = CRM_Export_BAO_Export
::exportComponents(
89 $this->contributionIDs
,
94 CRM_Export_Form_Select
::CONTRIBUTE_EXPORT
,
95 'civicrm_contribution.id IN ( ' . implode(',', $this->contributionIDs
) . ')',
100 'exportOption' => CRM_Export_Form_Select
::CONTRIBUTE_EXPORT
,
101 'suppress_csv_for_testing' => TRUE,
105 // delete the export temp table and component table
106 $sql = "DROP TABLE IF EXISTS {$tableName}";
107 CRM_Core_DAO
::executeQuery($sql);
111 * Basic test to ensure the exportComponents function can export selected fields for contribution.
113 public function testExportComponentsActivity() {
114 $this->setUpActivityExportData();
115 $selectedFields = array(
116 array('Individual', 'display_name'),
117 array('Individual', '5_a_b', 'display_name'),
120 list($tableName) = CRM_Export_BAO_Export
::exportComponents(
124 '`activity_date_time` desc',
127 CRM_Export_Form_Select
::ACTIVITY_EXPORT
,
128 'civicrm_activity.id IN ( ' . implode(',', $this->activityIDs
) . ')',
133 'exportOption' => CRM_Export_Form_Select
::ACTIVITY_EXPORT
,
134 'suppress_csv_for_testing' => TRUE,
138 // delete the export temp table and component table
139 $sql = "DROP TABLE IF EXISTS {$tableName}";
140 CRM_Core_DAO
::executeQuery($sql);
144 * Test the function that extracts the arrays used to structure the output.
146 * The keys in the output fields array should by matched by field aliases in the sql query (with
147 * exceptions of course - currently country is one - although maybe a future refactor can change that!).
149 * We are trying to move towards simpler processing in the per row iteration as that may be
150 * repeated 100,000 times and in general we should simply be able to match the query fields to
151 * our expected rows & do a little pseudoconstant mapping.
153 public function testGetExportStructureArrays() {
154 // This is how return properties are formatted internally within the function for passing to the BAO query.
155 $returnProperties = array(
159 'contribution_source' => 1,
162 'street_address' => 1,
173 'contribution_id' => 1,
176 $contactRelationshipTypes = CRM_Contact_BAO_Relationship
::getContactRelationshipType(
186 $query = new CRM_Contact_BAO_Query(array(), $returnProperties, NULL,
187 FALSE, FALSE, CRM_Contact_BAO_Query
::MODE_CONTRIBUTE
,
188 FALSE, TRUE, TRUE, NULL, 'AND'
191 list($select) = $query->query();
192 $pattern = '/as `?([^`,]*)/';
193 $queryFieldAliases = array();
194 preg_match_all($pattern, $select, $queryFieldAliases, PREG_PATTERN_ORDER
);
196 list($outputFields) = CRM_Export_BAO_Export
::getExportStructureArrays($returnProperties, $query, $contactRelationshipTypes, '', array());
197 foreach (array_keys($outputFields) as $fieldAlias) {
198 if ($fieldAlias == 'Home-country') {
199 $this->assertTrue(in_array($fieldAlias . '_id', $queryFieldAliases[1]), 'Country is subject to some funky translate so we make sure country id is present');
202 $this->assertTrue(in_array($fieldAlias, $queryFieldAliases[1]), 'looking for field ' . $fieldAlias . ' in generaly the alias fields need to match the outputfields');
209 * Set up some data for us to do testing on.
211 public function setUpContributionExportData() {
212 $this->setUpContactExportData();
213 $this->contributionIDs
[] = $this->contributionCreate(array('contact_id' => $this->contactIDs
[0], 'trxn_id' => 'null', 'invoice_id' => 'null'));
214 $this->contributionIDs
[] = $this->contributionCreate(array('contact_id' => $this->contactIDs
[1], 'trxn_id' => 'null', 'invoice_id' => 'null'));
218 * Set up some data for us to do testing on.
220 public function setUpActivityExportData() {
221 $this->setUpContactExportData();
222 $this->activityIDs
[] = $this->activityCreate(array('contact_id' => $this->contactIDs
[0]))['id'];
226 * Set up some data for us to do testing on.
228 public function setUpContactExportData() {
229 $this->contactIDs
[] = $contactA = $this->individualCreate(['gender_id' => 'Female']);
230 // Create address for contact A.
232 'contact_id' => $contactA,
233 'location_type_id' => 'Home',
234 'street_address' => 'Ambachtstraat 23',
235 'postal_code' => '6971 BN',
236 'country_id' => '1152',
240 $result = $this->callAPISuccess('address', 'create', $params);
241 $addressId = $result['id'];
243 $this->callAPISuccess('email', 'create', array(
244 'id' => $this->callAPISuccessGetValue('Email', ['contact_id' => $params['contact_id'], 'return' => 'id']),
245 'location_type_id' => 'Home',
246 'email' => 'home@example.com',
249 $this->callAPISuccess('email', 'create', array('contact_id' => $params['contact_id'], 'location_type_id' => 'Work', 'email' => 'work@example.com', 'is_primary' => 0));
251 $params['is_primary'] = 0;
252 $params['location_type_id'] = 'Work';
253 $this->callAPISuccess('address', 'create', $params);
254 $this->contactIDs
[] = $contactB = $this->individualCreate();
256 $this->callAPISuccess('address', 'create', array(
257 'contact_id' => $contactB,
258 'location_type_id' => "Home",
259 'master_id' => $addressId,
261 $this->masterAddressID
= $addressId;
266 * Test variants of primary address exporting.
268 * @param int $isPrimaryOnly
270 * @dataProvider getPrimarySearchOptions
272 public function testExportPrimaryAddress($isPrimaryOnly) {
273 \Civi
::settings()->set('searchPrimaryDetailsOnly', $isPrimaryOnly);
274 $this->setUpContactExportData();
276 $selectedFields = [['Individual', 'email', ' '], ['Individual', 'email', '1'], ['Individual', 'email', '2']];
277 list($tableName) = CRM_Export_BAO_Export
::exportComponents(
280 [['email', 'LIKE', 'c', 0, 1]],
284 CRM_Export_Form_Select
::CONTACT_EXPORT
,
285 "contact_a.id IN ({$this->contactIDs[0]}, {$this->contactIDs[1]})",
290 'exportOption' => CRM_Export_Form_Select
::CONTACT_EXPORT
,
291 'suppress_csv_for_testing' => TRUE,
295 $dao = CRM_Core_DAO
::executeQuery('SELECT * from ' . $tableName);
297 $this->assertEquals('home@example.com', $dao->email
);
298 $this->assertEquals('work@example.com', $dao->work_email
);
299 $this->assertEquals('home@example.com', $dao->home_email
);
300 $this->assertEquals(2, $dao->N
);
301 \Civi
::settings()->set('searchPrimaryDetailsOnly', FALSE);
305 * Get the options for the primary search setting field.
308 public function getPrimarySearchOptions() {
309 return [[TRUE], [FALSE]];
313 * Test that when exporting a pseudoField it is reset for NULL entries.
315 * ie. we have a contact WITH a gender & one without - make sure the latter one
316 * does NOT retain the gender of the former.
318 public function testExportPseudoField() {
319 $this->setUpContactExportData();
320 $selectedFields = [['Individual', 'gender_id']];
321 list($tableName, $sqlColumns) = CRM_Export_BAO_Export
::exportComponents(
323 $this->contactIDs
[1],
328 CRM_Export_Form_Select
::CONTACT_EXPORT
,
329 "contact_a.id IN (" . implode(",", $this->contactIDs
) . ")",
334 'exportOption' => CRM_Export_Form_Select
::CONTACT_EXPORT
,
335 'suppress_csv_for_testing' => TRUE,
338 $this->assertEquals('Female,', CRM_Core_DAO
::singleValueQuery("SELECT GROUP_CONCAT(gender_id) FROM {$tableName}"));
342 * Test that when exporting a pseudoField it is reset for NULL entries.
344 * This is specific to the example in CRM-14398
346 public function testExportPseudoFieldCampaign() {
347 $this->setUpContributionExportData();
348 $campaign = $this->callAPISuccess('Campaign', 'create', ['title' => 'Big campaign']);
349 $this->callAPISuccess('Contribution', 'create', ['campaign_id' => 'Big_campaign', 'id' => $this->contributionIDs
[0]]);
350 $selectedFields = [['Individual', 'gender_id'], ['Contribution', 'contribution_campaign_title']];
351 list($tableName, $sqlColumns) = CRM_Export_BAO_Export
::exportComponents(
353 $this->contactIDs
[1],
358 CRM_Export_Form_Select
::CONTRIBUTE_EXPORT
,
359 "contact_a.id IN (" . implode(",", $this->contactIDs
) . ")",
364 'exportOption' => CRM_Export_Form_Select
::CONTACT_EXPORT
,
365 'suppress_csv_for_testing' => TRUE,
368 $this->assertEquals('Big campaign,', CRM_Core_DAO
::singleValueQuery("SELECT GROUP_CONCAT(contribution_campaign_title) FROM {$tableName}"));
372 * Test exporting relationships.
374 * This is to ensure that CRM-13995 remains fixed.
376 public function testExportRelationshipsMergeToHousehold() {
377 list($householdID, $houseHoldTypeID) = $this->setUpHousehold();
380 ['Individual', $houseHoldTypeID . '_a_b', 'state_province', ''],
381 ['Individual', $houseHoldTypeID . '_a_b', 'city', ''],
382 ['Individual', 'city', ''],
383 ['Individual', 'state_province', ''],
385 list($tableName) = CRM_Export_BAO_Export
::exportComponents(
392 CRM_Export_Form_Select
::CONTACT_EXPORT
,
393 "contact_a.id IN (" . implode(",", $this->contactIDs
) . ")",
398 'exportOption' => CRM_Export_Form_Select
::CONTACT_EXPORT
,
399 'suppress_csv_for_testing' => TRUE,
402 $dao = CRM_Core_DAO
::executeQuery("SELECT * FROM {$tableName}");
403 while ($dao->fetch()) {
404 $this->assertEquals('Portland', $dao->city
);
405 $this->assertEquals('ME', $dao->state_province
);
406 $this->assertEquals($householdID, $dao->civicrm_primary_id
);
407 $this->assertEquals($householdID, $dao->civicrm_primary_id
);
413 * Test exporting relationships.
415 public function testExportRelationshipsMergeToHouseholdAllFields() {
416 $this->markTestIncomplete('Does not yet work under CI due to mysql limitation (number of columns in table). Works on some boxes');
417 list($householdID) = $this->setUpHousehold();
418 list($tableName) = CRM_Export_BAO_Export
::exportComponents(
425 CRM_Export_Form_Select
::CONTACT_EXPORT
,
426 "contact_a.id IN (" . implode(",", $this->contactIDs
) . ")",
431 'exportOption' => CRM_Export_Form_Select
::CONTACT_EXPORT
,
432 'suppress_csv_for_testing' => TRUE,
435 $dao = CRM_Core_DAO
::executeQuery("SELECT * FROM {$tableName}");
436 while ($dao->fetch()) {
437 $this->assertEquals('Portland', $dao->city
);
438 $this->assertEquals('ME', $dao->state_province
);
439 $this->assertEquals($householdID, $dao->civicrm_primary_id
);
440 $this->assertEquals($householdID, $dao->civicrm_primary_id
);
441 $this->assertEquals('Unit Test Household', $dao->addressee
);
442 $this->assertEquals('Unit Test Household', $dao->display_name
);
447 * Test master_address_id field.
449 public function testExportMasterAddress() {
450 $this->setUpContactExportData();
452 //export the master address for contact B
453 $selectedFields = array(
454 array('Individual', 'master_id', 1),
456 list($tableName, $sqlColumns) = CRM_Export_BAO_Export
::exportComponents(
458 array($this->contactIDs
[1]),
463 CRM_Export_Form_Select
::CONTACT_EXPORT
,
464 "contact_a.id IN ({$this->contactIDs[1]})",
469 'exportOption' => CRM_Export_Form_Select
::CONTACT_EXPORT
,
470 'suppress_csv_for_testing' => TRUE,
473 $field = key($sqlColumns);
475 //assert the exported result
476 $masterName = CRM_Core_DAO
::singleValueQuery("SELECT {$field} FROM {$tableName}");
477 $displayName = CRM_Contact_BAO_Contact
::getMasterDisplayName($this->masterAddressID
);
478 $this->assertEquals($displayName, $masterName);
480 // delete the export temp table and component table
481 $sql = "DROP TABLE IF EXISTS {$tableName}";
482 CRM_Core_DAO
::executeQuery($sql);
486 * Test that deceased and do not mail contacts are removed from contacts before
488 public function testExportDeceasedDoNotMail() {
489 $contactA = $this->callAPISuccess('contact', 'create', array(
490 'first_name' => 'John',
491 'last_name' => 'Doe',
492 'contact_type' => 'Individual',
495 $contactB = $this->callAPISuccess('contact', 'create', array(
496 'first_name' => 'Jane',
497 'last_name' => 'Doe',
498 'contact_type' => 'Individual',
502 //create address for contact A
503 $result = $this->callAPISuccess('address', 'create', array(
504 'contact_id' => $contactA['id'],
505 'location_type_id' => 'Home',
506 'street_address' => 'ABC 12',
507 'postal_code' => '123 AB',
508 'country_id' => '1152',
513 //create address for contact B
514 $result = $this->callAPISuccess('address', 'create', array(
515 'contact_id' => $contactB['id'],
516 'location_type_id' => 'Home',
517 'street_address' => 'ABC 12',
518 'postal_code' => '123 AB',
519 'country_id' => '1152',
524 //export and merge contacts with same address
525 list($tableName, $sqlColumns) = CRM_Export_BAO_Export
::exportComponents(
527 array($contactA['id'], $contactB['id']),
532 CRM_Export_Form_Select
::CONTACT_EXPORT
,
533 "contact_a.id IN ({$contactA['id']}, {$contactB['id']})",
538 'exportOption' => CRM_Export_Form_Select
::CONTACT_EXPORT
,
539 'mergeOption' => TRUE,
540 'suppress_csv_for_testing' => TRUE,
541 'postal_mailing_export' => array(
542 'postal_mailing_export' => TRUE,
547 $greeting = CRM_Core_DAO
::singleValueQuery("SELECT email_greeting FROM {$tableName}");
549 //Assert email_greeting is not merged
550 $this->assertNotContains(',', (string) $greeting);
552 // delete the export temp table and component table
553 $sql = "DROP TABLE IF EXISTS {$tableName}";
554 CRM_Core_DAO
::executeQuery($sql);
560 protected function setUpHousehold() {
561 $this->setUpContactExportData();
562 $householdID = $this->householdCreate([
563 'api.Address.create' => [
564 'city' => 'Portland',
565 'state_province_id' => 'Maine',
566 'location_type_id' => 'Home'
570 $relationshipTypes = $this->callAPISuccess('RelationshipType', 'get', [])['values'];
571 $houseHoldTypeID = NULL;
572 foreach ($relationshipTypes as $id => $relationshipType) {
573 if ($relationshipType['name_a_b'] === 'Household Member of') {
574 $houseHoldTypeID = $relationshipType['id'];
577 $this->callAPISuccess('Relationship', 'create', [
578 'contact_id_a' => $this->contactIDs
[0],
579 'contact_id_b' => $householdID,
580 'relationship_type_id' => $houseHoldTypeID,
582 $this->callAPISuccess('Relationship', 'create', [
583 'contact_id_a' => $this->contactIDs
[1],
584 'contact_id_b' => $householdID,
585 'relationship_type_id' => $houseHoldTypeID,
587 return array($householdID, $houseHoldTypeID);