From 962f4484b3c1b743d93d48a22fc80e3bff39c44f Mon Sep 17 00:00:00 2001 From: eileen Date: Tue, 28 Jun 2016 14:59:57 +1200 Subject: [PATCH] CRM-19015 Merge data loss on zero fields (batch mode) --- CRM/Contact/BAO/Query.php | 33 +++++++-- tests/phpunit/api/v3/JobTest.php | 112 +++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 7 deletions(-) diff --git a/CRM/Contact/BAO/Query.php b/CRM/Contact/BAO/Query.php index 95a66627f7..4260f828a3 100644 --- a/CRM/Contact/BAO/Query.php +++ b/CRM/Contact/BAO/Query.php @@ -2159,8 +2159,7 @@ class CRM_Contact_BAO_Query { ); } elseif ($name === 'is_deceased') { - $this->_where[$grouping][] = self::buildClause("contact_a.{$name}", $op, $value); - $this->_qill[$grouping][] = "$field[title] $op \"$value\""; + $this->setQillAndWhere($name, $op, $value, $grouping, $field); self::$_openedPanes[ts('Demographics')] = TRUE; } elseif ($name === 'created_date' || $name === 'modified_date' || $name === 'deceased_date' || $name === 'birth_date') { @@ -2237,14 +2236,11 @@ class CRM_Contact_BAO_Query { $value = self::getWildCardedValue($wildcard, $op, $value); } - $wc = 'civicrm_website.url'; - $this->_where[$grouping][] = $d = self::buildClause($wc, $op, $value); + $this->_where[$grouping][] = $d = self::buildClause('civicrm_website.url', $op, $value); $this->_qill[$grouping][] = "$field[title] $op \"$value\""; } elseif ($name === 'contact_is_deleted') { - $this->_where[$grouping][] = self::buildClause("contact_a.is_deleted", $op, $value); - list($qillop, $qillVal) = CRM_Contact_BAO_Query::buildQillForFieldValue(NULL, $name, $value, $op); - $this->_qill[$grouping][] = ts("%1 %2 %3", array(1 => $field['title'], 2 => $qillop, 3 => $qillVal)); + $this->setQillAndWhere('is_deleted', $op, $value, $grouping, $field); } elseif (!empty($field['where'])) { $type = NULL; @@ -6162,6 +6158,29 @@ AND displayRelType.is_active = 1 // Note that groups that the user does not have permission to will be excluded (good). $groups = array_intersect_key($allGroups, array_flip($groupIDs)); return implode(', ', $groups); + + } + + /** + * Set the qill and where properties for a field. + * + * This function is intended as a short-term function to encourage refactoring + * & re-use - but really we should just have less special-casing. + * + * @param string $name + * @param string $op + * @param string|array $value + * @param string $grouping + * @param string $field + */ + public function setQillAndWhere($name, $op, $value, $grouping, $field) { + $this->_where[$grouping][] = self::buildClause("contact_a.{$name}", $op, $value); + list($qillop, $qillVal) = CRM_Contact_BAO_Query::buildQillForFieldValue(NULL, $name, $value, $op); + $this->_qill[$grouping][] = ts("%1 %2 %3", array( + 1 => $field['title'], + 2 => $qillop, + 3 => $qillVal, + )); } } diff --git a/tests/phpunit/api/v3/JobTest.php b/tests/phpunit/api/v3/JobTest.php index 5d450396b7..770ece7d8c 100644 --- a/tests/phpunit/api/v3/JobTest.php +++ b/tests/phpunit/api/v3/JobTest.php @@ -317,6 +317,30 @@ class api_v3_JobTest extends CiviUnitTestCase { $this->callAPISuccess('Contact', 'create', $params); } + $result = $this->callAPISuccess('Job', 'process_batch_merge', array('mode' => $dataSet['mode'])); + $this->assertEquals($dataSet['skipped'], count($result['values']['skipped']), 'Failed to skip the right number:' . $dataSet['skipped']); + $this->assertEquals($dataSet['merged'], count($result['values']['merged'])); + $result = $this->callAPISuccess('Contact', 'get', array('contact_sub_type' => 'Student', 'sequential' => 1, 'is_deceased' => array('IN' => array(0, 1)))); + $this->assertEquals(count($dataSet['expected']), $result['count']); + foreach ($dataSet['expected'] as $index => $contact) { + foreach ($contact as $key => $value) { + $this->assertEquals($value, $result['values'][$index][$key]); + } + } + } + + /** + * Test the batch merge function actually works! + * + * @dataProvider getMergeSets + * + * @param $dataSet + */ + public function testBatchMergeConflictOnDeceased($dataSet) { + foreach ($dataSet['contacts'] as $params) { + $this->callAPISuccess('Contact', 'create', $params); + } + $result = $this->callAPISuccess('Job', 'process_batch_merge', array('mode' => $dataSet['mode'])); $this->assertEquals($dataSet['skipped'], count($result['values']['skipped']), 'Failed to skip the right number:' . $dataSet['skipped']); $this->assertEquals($dataSet['merged'], count($result['values']['merged'])); @@ -642,6 +666,94 @@ class api_v3_JobTest extends CiviUnitTestCase { ), ), ), + array( + array( + 'mode' => 'safe', + 'contacts' => array( + array( + 'first_name' => 'Michael', + 'last_name' => 'Jackson', + 'email' => 'michael@neverland.com', + 'contact_type' => 'Individual', + 'contact_sub_type' => 'Student', + 'api.Address.create' => array( + 'street_address' => 'big house', + 'location_type_id' => 'Home', + ), + ), + array( + 'first_name' => 'Michael', + 'last_name' => 'Jackson', + 'email' => 'michael@neverland.com', + 'contact_type' => 'Individual', + 'contact_sub_type' => 'Student', + 'is_deceased' => 1, + ), + ), + 'skipped' => 1, + 'merged' => 0, + 'expected' => array( + array( + 'first_name' => 'Michael', + 'last_name' => 'Jackson', + 'email' => 'michael@neverland.com', + 'contact_type' => 'Individual', + 'is_deceased' => 0, + ), + array( + 'first_name' => 'Michael', + 'last_name' => 'Jackson', + 'email' => 'michael@neverland.com', + 'contact_type' => 'Individual', + 'is_deceased' => 1, + ), + ), + ), + ), + array( + array( + 'mode' => 'safe', + 'contacts' => array( + array( + 'first_name' => 'Michael', + 'last_name' => 'Jackson', + 'email' => 'michael@neverland.com', + 'contact_type' => 'Individual', + 'contact_sub_type' => 'Student', + 'api.Address.create' => array( + 'street_address' => 'big house', + 'location_type_id' => 'Home', + ), + 'is_deceased' => 1, + ), + array( + 'first_name' => 'Michael', + 'last_name' => 'Jackson', + 'email' => 'michael@neverland.com', + 'contact_type' => 'Individual', + 'contact_sub_type' => 'Student', + ), + ), + 'skipped' => 1, + 'merged' => 0, + 'expected' => array( + array( + 'first_name' => 'Michael', + 'last_name' => 'Jackson', + 'email' => 'michael@neverland.com', + 'contact_type' => 'Individual', + 'is_deceased' => 1, + ), + array( + 'first_name' => 'Michael', + 'last_name' => 'Jackson', + 'email' => 'michael@neverland.com', + 'contact_type' => 'Individual', + 'is_deceased' => 0, + ), + ), + ), + ), ); return $data; } -- 2.25.1