Skip to content

Commit

Permalink
Switch Contact import to use new v4 dedupe lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
eileenmcnaughton committed Aug 29, 2022
1 parent 7af1299 commit d5920b1
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 13 deletions.
37 changes: 26 additions & 11 deletions CRM/Contact/Import/Parser/Contact.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
*/

use Civi\Api4\Contact;
use Civi\Api4\DedupeRuleGroup;
use Civi\Api4\RelationshipType;
use Civi\Api4\StateProvince;

Expand Down Expand Up @@ -1050,29 +1051,27 @@ private function getSuccessMessage(): string {
*
* @param array $params
* @param int|null $extIDMatch
* @param int|null $dedupeRuleID
* @param int|string $dedupeRuleID
*
* @return int|null
* IDs of a possible.
*
* @throws \CRM_Core_Exception
* @throws \CiviCRM_API3_Exception
*/
protected function getPossibleContactMatch(array $params, ?int $extIDMatch, ?int $dedupeRuleID): ?int {
$checkParams = ['check_permissions' => FALSE, 'match' => $params, 'dedupe_rule_id' => $dedupeRuleID];
$possibleMatches = civicrm_api3('Contact', 'duplicatecheck', $checkParams);
protected function getPossibleContactMatch(array $params, ?int $extIDMatch, $dedupeRuleID): ?int {
$possibleMatches = $this->getPossibleMatchesByDedupeRule($params, $dedupeRuleID);
if (!$extIDMatch) {
if (count($possibleMatches['values']) === 1) {
return array_key_last($possibleMatches['values']);
if (count($possibleMatches) === 1) {
return array_key_last($possibleMatches);
}
if (count($possibleMatches['values']) > 1) {
if (count($possibleMatches) > 1) {
throw new CRM_Core_Exception(ts('Record duplicates multiple contacts: ') . implode(',', array_keys($possibleMatches['values'])), CRM_Import_Parser::ERROR);

}
return NULL;
}
if ($possibleMatches['count']) {
if (array_key_exists($extIDMatch, $possibleMatches['values'])) {
if (count($possibleMatches) > 0) {
if (array_key_exists($extIDMatch, $possibleMatches)) {
return $extIDMatch;
}
throw new CRM_Core_Exception(ts('Matching this contact based on the de-dupe rule would cause an external ID conflict'), CRM_Import_Parser::ERROR);
Expand Down Expand Up @@ -1635,7 +1634,7 @@ protected function lookupContactID(array $params, bool $isMainContact): ?int {
if (isset($params['relationship'])) {
unset($params['relationship']);
}
$id = $this->getPossibleContactMatch($params, $extIDMatch, $this->getSubmittedValue('dedupe_rule_id') ?: NULL);
$id = $this->getPossibleContactMatch($params, $extIDMatch, $this->getDedupeRuleName());
if ($id && $isMainContact && $this->isSkipDuplicates()) {
throw new CRM_Core_Exception(ts('Contact matched by dedupe rule already exists in the database.'), CRM_Import_Parser::DUPLICATE);
}
Expand All @@ -1644,6 +1643,22 @@ protected function lookupContactID(array $params, bool $isMainContact): ?int {
return NULL;
}

/**
* Get the unique name of the rule group to use.
*
* @return string
*
* @throws \API_Exception
*/
protected function getDedupeRuleName(): string {
if ($this->getSubmittedValue('dedupe_rule_id')) {
return DedupeRuleGroup::get(FALSE)
->addWhere('id', '=', $this->getSubmittedValue('dedupe_rule_id'))
->addSelect('name')->execute()->first()['name'];
}
return $this->getContactType() . '.Unsupervised';
}

/**
* @param array $params
* @param array $formatted
Expand Down
63 changes: 62 additions & 1 deletion CRM/Import/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -1592,7 +1592,7 @@ protected function getContactMatchingFields(): array {
* @throws \API_Exception
*/
protected function getFieldEntity(string $fieldName) {
if ($fieldName === 'do_not_import') {
if ($fieldName === 'do_not_import' || $fieldName === '') {
return '';
}
if (in_array($fieldName, ['email_greeting_id', 'postal_greeting_id', 'addressee_id'], TRUE)) {
Expand Down Expand Up @@ -2026,4 +2026,65 @@ protected function lookupExternalIdentifier(?string $externalIdentifier, string
return (int) $foundContact['id'];
}

/**
* Get contacts that match the input parameters, using a dedupe rule.
*
* @param array $params
* @param string|int $dedupeRuleID
*
* @return array
*
* @throws \CRM_Core_Exception
*/
protected function getPossibleMatchesByDedupeRule(array $params, $dedupeRuleID): array {
foreach (['email', 'address', 'phone', 'im'] as $locationEntity) {
if (array_key_exists($locationEntity, $params)) {
// Prefer primary
if (array_key_exists('Primary', $params[$locationEntity])) {
$locationParams = $params[$locationEntity]['Primary'];
}
else {
// Chose the first one - at least they can manipulate the order.
$locationParams = reset($params[$locationEntity]);
}
foreach ($locationParams as $key => $locationParam) {
// Even though we might not be using 'primary' we 'pretend' here
// since the apiv4 code expects that...
$params[$locationEntity . '_primary' . '.' . $key] = $locationParam;
}
unset($params[$locationEntity]);
}
}
foreach ($params as $key => $value) {
if (strpos($key, 'custom_') === 0) {
$params[$this->getApi4Name($key)] = $value;
unset($params[$key]);
}
}
$possibleMatches = Contact::getDuplicates(FALSE)
->setValues($params)
->setDedupeRule($dedupeRuleID)
->execute();

$matchIDs = [];
foreach ($possibleMatches as $possibleMatch) {
$matchIDs[$possibleMatch['id']] = $possibleMatch['id'];
}
return $matchIDs;
}

/**
* Get the Api4 name of a custom field.
*
* @param string $key
*
* @throws \CRM_Core_Exception
*/
protected function getApi4Name(string $key): string {
return Contact::getFields(FALSE)
->addWhere('custom_field_id', '=', $this->getFieldMetadata($key)['custom_field_id'])
->addSelect('name')
->execute()->first()['name'];
}

}
1 change: 0 additions & 1 deletion tests/phpunit/CRM/Contact/Import/Parser/ContactTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,6 @@ public function testContactLocationBlockHandling(): void {
$this->callAPISuccessGetCount('IM', ['contact_id' => $id], 1);
}


/**
* Test whether importing a contact using email match will match a non-primary.
*
Expand Down

0 comments on commit d5920b1

Please sign in to comment.