From b36dc5b8c66ee098a60836da0148fb90fd32dc1a Mon Sep 17 00:00:00 2001 From: eileen Date: Mon, 17 Feb 2020 10:26:03 +1300 Subject: [PATCH] dev/core#1597 & dev/core#1595 fix regression when deduping on custom fields --- CRM/Dedupe/BAO/Rule.php | 26 +++++++- tests/phpunit/CRM/Dedupe/DedupeFinderTest.php | 60 +++++++++++++------ 2 files changed, 65 insertions(+), 21 deletions(-) diff --git a/CRM/Dedupe/BAO/Rule.php b/CRM/Dedupe/BAO/Rule.php index 6ff97260ee6d..ec4a0cfded8b 100644 --- a/CRM/Dedupe/BAO/Rule.php +++ b/CRM/Dedupe/BAO/Rule.php @@ -58,15 +58,13 @@ public function sql() { // full matches, respectively) $where = []; $on = ["SUBSTR(t1.{$this->rule_field}, 1, {$this->rule_length}) = SUBSTR(t2.{$this->rule_field}, 1, {$this->rule_length})"]; - $entity = CRM_Core_DAO_AllCoreTables::getBriefName(CRM_Core_DAO_AllCoreTables::getClassForTable($this->rule_table)); - $fields = civicrm_api3($entity, 'getfields', ['action' => 'create'])['values']; $innerJoinClauses = [ "t1.{$this->rule_field} IS NOT NULL", "t2.{$this->rule_field} IS NOT NULL", "t1.{$this->rule_field} = t2.{$this->rule_field}", ]; - if ($fields[$this->rule_field]['type'] === CRM_Utils_Type::T_DATE) { + if ($this->getFieldType($this->rule_field) === CRM_Utils_Type::T_DATE) { $innerJoinClauses[] = "t1.{$this->rule_field} > '1000-01-01'"; $innerJoinClauses[] = "t2.{$this->rule_field} > '1000-01-01'"; } @@ -238,4 +236,26 @@ public static function validateContacts($cid, $oid) { return $exception->find(TRUE) ? FALSE : TRUE; } + /** + * Get the specification for the given field. + * + * @param string $fieldName + * + * @return array + * @throws \CiviCRM_API3_Exception + */ + public function getFieldType($fieldName) { + $entity = CRM_Core_DAO_AllCoreTables::getBriefName(CRM_Core_DAO_AllCoreTables::getClassForTable($this->rule_table)); + if (!$entity) { + // This means we have stored a custom field rather than an entity name in rule_table, figure out the entity. + $entity = civicrm_api3('CustomGroup', 'getvalue', ['table_name' => $this->rule_table, 'return' => 'extends']); + if (in_array($entity, ['Individual', 'Household', 'Organization'])) { + $entity = 'Contact'; + } + $fieldName = 'custom_' . civicrm_api3('CustomField', 'getvalue', ['column_name' => $fieldName, 'return' => 'id']); + } + $fields = civicrm_api3($entity, 'getfields', ['action' => 'create'])['values']; + return $fields[$fieldName]['type']; + } + } diff --git a/tests/phpunit/CRM/Dedupe/DedupeFinderTest.php b/tests/phpunit/CRM/Dedupe/DedupeFinderTest.php index 0666a70854c4..71c56c315c39 100644 --- a/tests/phpunit/CRM/Dedupe/DedupeFinderTest.php +++ b/tests/phpunit/CRM/Dedupe/DedupeFinderTest.php @@ -6,6 +6,7 @@ */ class CRM_Dedupe_DedupeFinderTest extends CiviUnitTestCase { + use CRMTraits_Custom_CustomDataTrait; /** * IDs of created contacts. * @@ -31,6 +32,10 @@ public function tearDown() { if ($this->groupID) { $this->callAPISuccess('group', 'delete', ['id' => $this->groupID]); } + $this->quickCleanup(['civicrm_contact'], TRUE); + CRM_Core_DAO::executeQuery("DELETE r FROM civicrm_dedupe_rule_group rg INNER JOIN civicrm_dedupe_rule r ON rg.id = r.dedupe_rule_group_id WHERE rg.is_reserved = 0 AND used = 'General'"); + CRM_Core_DAO::executeQuery("DELETE FROM civicrm_dedupe_rule_group WHERE is_reserved = 0 AND used = 'General'"); + parent::tearDown(); } @@ -88,15 +93,7 @@ public function testUnsupervisedWithTwoEmailFields() { public function testCustomRule() { $this->setupForGroupDedupe(); - $ruleGroup = $this->callAPISuccess('RuleGroup', 'create', [ - 'contact_type' => 'Individual', - 'threshold' => 8, - 'used' => 'General', - 'name' => 'TestRule', - 'title' => 'TestRule', - 'is_reserved' => 0, - ]); - $rules = []; + $ruleGroup = $this->createRuleGroup(); foreach (['birth_date', 'first_name', 'last_name'] as $field) { $rules[$field] = $this->callAPISuccess('Rule', 'create', [ 'dedupe_rule_group_id' => $ruleGroup['id'], @@ -111,6 +108,25 @@ public function testCustomRule() { } + /** + * Test that we do not get a fatal error when our rule group is a custom date field. + * + * @throws \CRM_Core_Exception + */ + public function testCustomRuleCustomDateField() { + + $ruleGroup = $this->createRuleGroup(); + $this->createCustomGroupWithFieldOfType([], 'date'); + $this->callAPISuccess('Rule', 'create', [ + 'dedupe_rule_group_id' => $ruleGroup['id'], + 'rule_table' => $this->getCustomGroupTable(), + 'rule_weight' => 4, + 'rule_field' => $this->getCustomFieldColumnName('date'), + ]); + + CRM_Dedupe_Finder::dupes($ruleGroup['id']); + } + /** * Test a custom rule with a non-default field. */ @@ -173,15 +189,7 @@ public function testRuleThreeContactFieldsEqualWeightWIthThresholdtheTotalSumOfA public function testInclusiveRule() { $this->setupForGroupDedupe(); - $ruleGroup = $this->callAPISuccess('RuleGroup', 'create', [ - 'contact_type' => 'Individual', - 'threshold' => 8, - 'used' => 'General', - 'name' => 'TestRule', - 'title' => 'TestRule', - 'is_reserved' => 0, - ]); - $rules = []; + $ruleGroup = $this->createRuleGroup(); foreach (['first_name', 'last_name'] as $field) { $rules[$field] = $this->callAPISuccess('Rule', 'create', [ 'dedupe_rule_group_id' => $ruleGroup['id'], @@ -424,4 +432,20 @@ protected function setupForGroupDedupe() { $this->assertEquals(count($this->contactIDs), 7, 'Check for number of contacts.'); } + /** + * @return array|int + * @throws \CRM_Core_Exception + */ + protected function createRuleGroup() { + $ruleGroup = $this->callAPISuccess('RuleGroup', 'create', [ + 'contact_type' => 'Individual', + 'threshold' => 8, + 'used' => 'General', + 'name' => 'TestRule', + 'title' => 'TestRule', + 'is_reserved' => 0, + ]); + return $ruleGroup; + } + }