/** * Function to pre processing * * @return None * @access public */ function preProcess() { $this->_rgid = CRM_Utils_Request::retrieve('id', 'Positive', $this, false, 0); $this->_contactType = CRM_Utils_Request::retrieve('contact_type', 'String', $this, false, 0); if ($this->_rgid) { $rgDao =& new CRM_Dedupe_DAO_RuleGroup(); $rgDao->id = $this->_rgid; $rgDao->find(true); $this->_defaults['threshold'] = $rgDao->threshold; $this->_contactType = $rgDao->contact_type; $this->_defaults['level'] = $rgDao->level; $this->_defaults['name'] = $rgDao->name; $ruleDao =& new CRM_Dedupe_DAO_Rule(); $ruleDao->dedupe_rule_group_id = $this->_rgid; $ruleDao->find(); $count = 0; while ($ruleDao->fetch()) { $this->_defaults["where_{$count}"] = "{$ruleDao->rule_table}.{$ruleDao->rule_field}"; $this->_defaults["length_{$count}"] = $ruleDao->rule_length; $this->_defaults["weight_{$count}"] = $ruleDao->rule_weight; $count++; } } $supported =& CRM_Dedupe_BAO_RuleGroup::supportedFields($this->_contactType); if (is_array($supported)) { foreach ($supported as $table => $fields) { foreach ($fields as $field => $title) { $this->_fields["{$table}.{$field}"] = $title; } } } asort($this->_fields); }
/** * Pre processing. * * @return void */ public function preProcess() { // Ensure user has permission to be here if (!CRM_Core_Permission::check('administer dedupe rules')) { CRM_Utils_System::permissionDenied(); CRM_Utils_System::civiExit(); } $this->_options = CRM_Core_SelectValues::getDedupeRuleTypes(); $this->_rgid = CRM_Utils_Request::retrieve('id', 'Positive', $this, FALSE, 0); $this->_contactType = CRM_Utils_Request::retrieve('contact_type', 'String', $this, FALSE, 0); if ($this->_rgid) { $rgDao = new CRM_Dedupe_DAO_RuleGroup(); $rgDao->id = $this->_rgid; $rgDao->find(TRUE); $this->_defaults['threshold'] = $rgDao->threshold; $this->_contactType = $rgDao->contact_type; $this->_defaults['used'] = CRM_Utils_Array::key($rgDao->used, $this->_options); $this->_defaults['title'] = $rgDao->title; $this->_defaults['name'] = $rgDao->name; $this->_defaults['is_reserved'] = $rgDao->is_reserved; $this->assign('isReserved', $rgDao->is_reserved); $this->assign('ruleName', $rgDao->name); $ruleDao = new CRM_Dedupe_DAO_Rule(); $ruleDao->dedupe_rule_group_id = $this->_rgid; $ruleDao->find(); $count = 0; while ($ruleDao->fetch()) { $this->_defaults["where_{$count}"] = "{$ruleDao->rule_table}.{$ruleDao->rule_field}"; $this->_defaults["length_{$count}"] = $ruleDao->rule_length; $this->_defaults["weight_{$count}"] = $ruleDao->rule_weight; $count++; } } $supported = CRM_Dedupe_BAO_RuleGroup::supportedFields($this->_contactType); if (is_array($supported)) { foreach ($supported as $table => $fields) { foreach ($fields as $field => $title) { $this->_fields["{$table}.{$field}"] = $title; } } } asort($this->_fields); }
/** * Function to pre processing * * @return None * @access public */ function preProcess() { // Ensure user has permission to be here require_once 'CRM/Core/Permission.php'; if (!CRM_Core_Permission::check('administer dedupe rules')) { CRM_Utils_System::permissionDenied(); CRM_Utils_System::civiExit(); } $this->_rgid = CRM_Utils_Request::retrieve('id', 'Positive', $this, false, 0); $this->_contactType = CRM_Utils_Request::retrieve('contact_type', 'String', $this, false, 0); if ($this->_rgid) { $rgDao = new CRM_Dedupe_DAO_RuleGroup(); $rgDao->id = $this->_rgid; $rgDao->find(true); $this->_defaults['threshold'] = $rgDao->threshold; $this->_contactType = $rgDao->contact_type; $this->_defaults['level'] = $rgDao->level; $this->_defaults['name'] = $rgDao->name; $this->_defaults['is_default'] = $rgDao->is_default; $ruleDao = new CRM_Dedupe_DAO_Rule(); $ruleDao->dedupe_rule_group_id = $this->_rgid; $ruleDao->find(); $count = 0; while ($ruleDao->fetch()) { $this->_defaults["where_{$count}"] = "{$ruleDao->rule_table}.{$ruleDao->rule_field}"; $this->_defaults["length_{$count}"] = $ruleDao->rule_length; $this->_defaults["weight_{$count}"] = $ruleDao->rule_weight; $count++; } } $supported =& CRM_Dedupe_BAO_RuleGroup::supportedFields($this->_contactType); if (is_array($supported)) { foreach ($supported as $table => $fields) { foreach ($fields as $field => $title) { $this->_fields["{$table}.{$field}"] = $title; } } } asort($this->_fields); }
/** * global validation rules for the form * * @param array $fields posted values of the form * * @return array list of errors to be posted back to the form * @static * @access public */ static function formRule($fields) { $errors = array(); // define so we avoid notices below $errors['_qf_default'] = ''; $fieldMessage = NULL; if (!array_key_exists('savedMapping', $fields)) { $importKeys = array(); foreach ($fields['mapper'] as $mapperPart) { $importKeys[] = $mapperPart[0]; } // FIXME: should use the schema titles, not redeclare them $requiredFields = array('target_contact_id' => ts('Contact ID'), 'activity_date_time' => ts('Activity Date'), 'activity_subject' => ts('Activity Subject'), 'activity_type_id' => ts('Activity Type Id')); $params = array('used' => 'Unsupervised', 'contact_type' => 'Individual'); list($ruleFields, $threshold) = CRM_Dedupe_BAO_RuleGroup::dedupeRuleFieldsWeight($params); $weightSum = 0; foreach ($importKeys as $key => $val) { if (array_key_exists($val, $ruleFields)) { $weightSum += $ruleFields[$val]; } } foreach ($ruleFields as $field => $weight) { $fieldMessage .= ' ' . $field . '(weight ' . $weight . ')'; } foreach ($requiredFields as $field => $title) { if (!in_array($field, $importKeys)) { if ($field == 'target_contact_id') { if ($weightSum >= $threshold || in_array('external_identifier', $importKeys)) { continue; } else { $errors['_qf_default'] .= ts('Missing required contact matching fields.') . $fieldMessage . ' ' . ts('(Sum of all weights should be greater than or equal to threshold: %1).', array(1 => $threshold)) . '<br />'; } } elseif ($field == 'activity_type_id') { if (in_array('activity_label', $importKeys)) { continue; } else { $errors['_qf_default'] .= ts('Missing required field: Provide %1 or %2', array(1 => $title, 2 => 'Activity Type Label')) . '<br />'; } } else { $errors['_qf_default'] .= ts('Missing required field: %1', array(1 => $title)) . '<br />'; } } } } if (!empty($fields['saveMapping'])) { $nameField = CRM_Utils_Array::value('saveMappingName', $fields); if (empty($nameField)) { $errors['saveMappingName'] = ts('Name is required to save Import Mapping'); } else { $mappingTypeId = CRM_Core_OptionGroup::getValue('mapping_type', 'Import Activity', 'name'); if (CRM_Core_BAO_Mapping::checkMapping($nameField, $mappingTypeId)) { $errors['saveMappingName'] = ts('Duplicate Import Mapping Name'); } } } if (empty($errors['_qf_default'])) { unset($errors['_qf_default']); } if (!empty($errors)) { if (!empty($errors['saveMappingName'])) { $_flag = 1; $assignError = new CRM_Core_Page(); $assignError->assign('mappingDetailsError', $_flag); } return $errors; } return TRUE; }
/** * Global validation rules for the form. * * @param array $fields * Posted values of the form. * * @param $files * @param $self * * @return array * list of errors to be posted back to the form */ public static function formRule($fields, $files, $self) { $errors = array(); $fieldMessage = NULL; $contactORContributionId = $self->_onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE ? 'contribution_id' : 'contribution_contact_id'; if (!array_key_exists('savedMapping', $fields)) { $importKeys = array(); foreach ($fields['mapper'] as $mapperPart) { $importKeys[] = $mapperPart[0]; } $contactTypeId = $self->get('contactType'); $contactTypes = array(CRM_Import_Parser::CONTACT_INDIVIDUAL => 'Individual', CRM_Import_Parser::CONTACT_HOUSEHOLD => 'Household', CRM_Import_Parser::CONTACT_ORGANIZATION => 'Organization'); $params = array('used' => 'Unsupervised', 'contact_type' => isset($contactTypes[$contactTypeId]) ? $contactTypes[$contactTypeId] : ''); list($ruleFields, $threshold) = CRM_Dedupe_BAO_RuleGroup::dedupeRuleFieldsWeight($params); $weightSum = 0; foreach ($importKeys as $key => $val) { if (array_key_exists($val, $ruleFields)) { $weightSum += $ruleFields[$val]; } if ($val == "soft_credit") { $mapperKey = CRM_Utils_Array::key('soft_credit', $importKeys); if (empty($fields['mapper'][$mapperKey][1])) { if (empty($errors['_qf_default'])) { $errors['_qf_default'] = ''; } $errors['_qf_default'] .= ts('Missing required fields: Soft Credit') . '<br />'; } } } foreach ($ruleFields as $field => $weight) { $fieldMessage .= ' ' . $field . '(weight ' . $weight . ')'; } // FIXME: should use the schema titles, not redeclare them $requiredFields = array($contactORContributionId == 'contribution_id' ? 'contribution_id' : 'contribution_contact_id' => $contactORContributionId == 'contribution_id' ? ts('Contribution ID') : ts('Contact ID'), 'total_amount' => ts('Total Amount'), 'financial_type' => ts('Financial Type')); foreach ($requiredFields as $field => $title) { if (!in_array($field, $importKeys)) { if (empty($errors['_qf_default'])) { $errors['_qf_default'] = ''; } if ($field == $contactORContributionId) { if (!($weightSum >= $threshold || in_array('external_identifier', $importKeys)) && $self->_onDuplicate != CRM_Import_Parser::DUPLICATE_UPDATE) { $errors['_qf_default'] .= ts('Missing required contact matching fields.') . " {$fieldMessage} " . ts('(Sum of all weights should be greater than or equal to threshold: %1).', array(1 => $threshold)) . '<br />'; } elseif ($self->_onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE && !(in_array('invoice_id', $importKeys) || in_array('trxn_id', $importKeys) || in_array('contribution_id', $importKeys))) { $errors['_qf_default'] .= ts('Invoice ID or Transaction ID or Contribution ID are required to match to the existing contribution records in Update mode.') . '<br />'; } } else { $errors['_qf_default'] .= ts('Missing required field: %1', array(1 => $title)) . '<br />'; } } } //at least one field should be mapped during update. if ($self->_onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE) { $atleastOne = FALSE; foreach ($self->_mapperFields as $key => $field) { if (in_array($key, $importKeys) && !in_array($key, array('doNotImport', 'contribution_id', 'invoice_id', 'trxn_id'))) { $atleastOne = TRUE; break; } } if (!$atleastOne) { $errors['_qf_default'] .= ts('At least one contribution field needs to be mapped for update during update mode.') . '<br />'; } } } if (!empty($fields['saveMapping'])) { $nameField = CRM_Utils_Array::value('saveMappingName', $fields); if (empty($nameField)) { $errors['saveMappingName'] = ts('Name is required to save Import Mapping'); } else { $mappingTypeId = CRM_Core_OptionGroup::getValue('mapping_type', 'Import Contribution', 'name'); if (CRM_Core_BAO_Mapping::checkMapping($nameField, $mappingTypeId)) { $errors['saveMappingName'] = ts('Duplicate Import Contribution Mapping Name'); } } } if (!empty($errors)) { if (!empty($errors['saveMappingName'])) { $_flag = 1; $assignError = new CRM_Core_Page(); $assignError->assign('mappingDetailsError', $_flag); } if (!empty($errors['_qf_default'])) { CRM_Core_Session::setStatus($errors['_qf_default'], ts("Error"), "error"); return $errors; } } return TRUE; }
/** * Given an array of contact ids this function will return array with links to view contact page. * * @param array $contactIDs * Associated contact id's. * @param bool $addViewLink * @param bool $addEditLink * @param int $originalId * Associated with the contact which is edited. * * * @return array * returns array with links to contact view */ public static function formatContactIDSToLinks($contactIDs, $addViewLink = TRUE, $addEditLink = TRUE, $originalId = NULL) { $contactLinks = array(); if (!is_array($contactIDs) || empty($contactIDs)) { return $contactLinks; } // does contact has sufficient permissions. $permissions = array('view' => 'view all contacts', 'edit' => 'edit all contacts', 'merge' => 'merge duplicate contacts'); $permissionedContactIds = array(); foreach ($permissions as $task => $permission) { // give permission. if (CRM_Core_Permission::check($permission)) { foreach ($contactIDs as $contactId) { $permissionedContactIds[$contactId][$task] = TRUE; } continue; } // check permission on acl basis. if (in_array($task, array('view', 'edit'))) { $aclPermission = CRM_Core_Permission::VIEW; if ($task == 'edit') { $aclPermission = CRM_Core_Permission::EDIT; } foreach ($contactIDs as $contactId) { if (CRM_Contact_BAO_Contact_Permission::allow($contactId, $aclPermission)) { $permissionedContactIds[$contactId][$task] = TRUE; } } } } // retrieve display names for all contacts $query = ' SELECT c.id, c.display_name, c.contact_type, ce.email FROM civicrm_contact c LEFT JOIN civicrm_email ce ON ( ce.contact_id=c.id AND ce.is_primary = 1 ) WHERE c.id IN (' . implode(',', $contactIDs) . ' ) LIMIT 20'; $dao = CRM_Core_DAO::executeQuery($query); $contactLinks['msg'] = NULL; $i = 0; while ($dao->fetch()) { $contactLinks['rows'][$i]['display_name'] = $dao->display_name; $contactLinks['rows'][$i]['primary_email'] = $dao->email; // get the permission for current contact id. $hasPermissions = CRM_Utils_Array::value($dao->id, $permissionedContactIds); if (!is_array($hasPermissions) || empty($hasPermissions)) { $i++; continue; } // do check for view. if (array_key_exists('view', $hasPermissions)) { $contactLinks['rows'][$i]['view'] = '<a class="action-item" href="' . CRM_Utils_System::url('civicrm/contact/view', 'reset=1&cid=' . $dao->id) . '" target="_blank">' . ts('View') . '</a>'; if (!$contactLinks['msg']) { $contactLinks['msg'] = 'view'; } } if (array_key_exists('edit', $hasPermissions)) { $contactLinks['rows'][$i]['edit'] = '<a class="action-item" href="' . CRM_Utils_System::url('civicrm/contact/add', 'reset=1&action=update&cid=' . $dao->id) . '" target="_blank">' . ts('Edit') . '</a>'; if (!$contactLinks['msg'] || $contactLinks['msg'] != 'merge') { $contactLinks['msg'] = 'edit'; } } if (!empty($originalId) && array_key_exists('merge', $hasPermissions)) { $rgBao = new CRM_Dedupe_BAO_RuleGroup(); $rgBao->contact_type = $dao->contact_type; $rgBao->used = 'Supervised'; if ($rgBao->find(TRUE)) { $rgid = $rgBao->id; } if ($rgid && isset($dao->id)) { //get an url to merge the contact $contactLinks['rows'][$i]['merge'] = '<a class="action-item" href="' . CRM_Utils_System::url('civicrm/contact/merge', "reset=1&cid=" . $originalId . '&oid=' . $dao->id . '&action=update&rgid=' . $rgid) . '">' . ts('Merge') . '</a>'; $contactLinks['msg'] = 'merge'; } } $i++; } return $contactLinks; }
/** * To find fields related to a rule group. * * @param array contains the rule group property to identify rule group * * @return rule fields array associated to rule group * @access public */ static function dedupeRuleFields($params) { $rgBao = new CRM_Dedupe_BAO_RuleGroup(); $rgBao->level = $params['level']; $rgBao->contact_type = $params['contact_type']; $rgBao->is_default = 1; $rgBao->find(TRUE); $ruleBao = new CRM_Dedupe_BAO_Rule(); $ruleBao->dedupe_rule_group_id = $rgBao->id; $ruleBao->find(); $ruleFields = array(); while ($ruleBao->fetch()) { $ruleFields[] = $ruleBao->rule_field; } return $ruleFields; }
/** * Check if the profiles collect enough information to dedupe. * * @param $profileIds * @param int $rgId * @return bool */ public static function canProfilesDedupe($profileIds, $rgId = 0) { // find the unsupervised rule $rgParams = array('used' => 'Unsupervised', 'contact_type' => 'Individual'); if ($rgId > 0) { $rgParams['id'] = $rgId; } $activeRg = CRM_Dedupe_BAO_RuleGroup::dedupeRuleFieldsWeight($rgParams); // get the combinations that could be a match for the rule $okCombos = $combos = array(); CRM_Dedupe_BAO_RuleGroup::combos($activeRg[0], $activeRg[1], $combos); // create an index of what combinations involve each field $index = array(); foreach ($combos as $comboid => $combo) { foreach ($combo as $cfield) { $index[$cfield][$comboid] = TRUE; } $combos[$comboid] = array_fill_keys($combo, 0); $okCombos[$comboid] = array_fill_keys($combo, 2); } // get profiles and see if they have the necessary combos $profileReqFields = array(); foreach ($profileIds as $profileId) { if ($profileId && is_numeric($profileId)) { $fields = CRM_Core_BAO_UFGroup::getFields($profileId); // walk through the fields in the profile foreach ($fields as $field) { // check each of the fields in the index against the profile field foreach ($index as $ifield => $icombos) { if (strpos($field['name'], $ifield) !== FALSE) { // we found the field in the profile, now record it in the index foreach ($icombos as $icombo => $dontcare) { $combos[$icombo][$ifield] = $combos[$icombo][$ifield] != 2 && !$field['is_required'] ? 1 : 2; if ($combos[$icombo] == $okCombos[$icombo]) { // if any combo is complete with 2s (all fields are present and required), we can go home return 2; } } } } } } } // check the combos to see if everything is > 0 foreach ($combos as $comboid => $combo) { $complete = FALSE; foreach ($combo as $cfield) { if ($cfield > 0) { $complete = TRUE; } else { // this combo isn't complete--skip to the next combo continue 2; } } if ($complete) { return 1; } } // no combo succeeded return 0; }
/** * find fields related to a rule group. * * @param array $params * * @return array * (rule field => weight) array and threshold associated to rule group */ public static function dedupeRuleFieldsWeight($params) { $rgBao = new CRM_Dedupe_BAO_RuleGroup(); $rgBao->contact_type = $params['contact_type']; if (!empty($params['id'])) { // accept an ID if provided $rgBao->id = $params['id']; } else { $rgBao->used = $params['used']; } $rgBao->find(TRUE); $ruleBao = new CRM_Dedupe_BAO_Rule(); $ruleBao->dedupe_rule_group_id = $rgBao->id; $ruleBao->find(); $ruleFields = array(); while ($ruleBao->fetch()) { $ruleFields[$ruleBao->rule_field] = $ruleBao->rule_weight; } return array($ruleFields, $rgBao->threshold); }
/** * Browse all rule groups. */ public function run() { $gid = CRM_Utils_Request::retrieve('gid', 'Positive', $this, FALSE, 0); $action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 0); $context = CRM_Utils_Request::retrieve('context', 'String', $this); $limit = CRM_Utils_Request::retrieve('limit', 'Integer', $this); $rgid = CRM_Utils_Request::retrieve('rgid', 'Positive'); $urlQry = "reset=1&rgid={$rgid}&gid={$gid}&limit={$limit}"; $this->assign('urlQuery', $urlQry); $session = CRM_Core_Session::singleton(); $contactIds = $session->get('selectedSearchContactIds'); if ($context == 'search' || !empty($contactIds)) { $context = 'search'; $this->assign('backURL', $session->readUserContext()); } if ($action & CRM_Core_Action::RENEW) { // empty cache if ($rgid) { CRM_Core_BAO_PrevNextCache::deleteItem(NULL, CRM_Dedupe_Merger::getMergeCacheKeyString($rgid, $gid)); } CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/dedupefind', $urlQry . "&action=update")); } elseif ($action & CRM_Core_Action::MAP) { // do a batch merge if requested $result = CRM_Dedupe_Merger::batchMerge($rgid, $gid, 'safe', TRUE, 75); $skippedCount = CRM_Utils_Request::retrieve('skipped', 'Positive', $this, FALSE, 0); $skippedCount = $skippedCount + count($result['skipped']); $mergedCount = CRM_Utils_Request::retrieve('merged', 'Positive', $this, FALSE, 0); $mergedCount = $mergedCount + count($result['merged']); if (empty($result['merged']) && empty($result['skipped'])) { $message = ''; if ($mergedCount >= 1) { $message = ts("%1 pairs of duplicates were merged", array(1 => $mergedCount)); } if ($skippedCount >= 1) { $message = $message ? "{$message} and " : ''; $message .= ts("%1 pairs of duplicates were skipped due to conflict", array(1 => $skippedCount)); } $message .= ts(" during the batch merge process with safe mode."); CRM_Core_Session::setStatus($message, ts('Merge Complete'), 'success'); CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/dedupefind', $urlQry . "&action=update")); } else { $urlQry .= "&action=map&skipped={$skippedCount}&merged={$mergedCount}"; CRM_Utils_System::jsRedirect(CRM_Utils_System::url('civicrm/contact/dedupefind', $urlQry), ts('Batch Merge Task in progress'), ts('The batch merge task is still in progress. This page will be refreshed automatically.')); } } if ($action & CRM_Core_Action::UPDATE || $action & CRM_Core_Action::BROWSE) { $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, FALSE, 0); $this->action = CRM_Core_Action::UPDATE; $urlQry .= '&snippet=4'; if ($context == 'conflicts') { $urlQry .= "&selected=1"; } $this->assign('sourceUrl', CRM_Utils_System::url('civicrm/ajax/dedupefind', $urlQry, FALSE, NULL, FALSE)); //reload from cache table $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($rgid, $gid); $stats = CRM_Dedupe_Merger::getMergeStatsMsg($cacheKeyString); if ($stats) { CRM_Core_Session::setStatus($stats); // reset so we not displaying same message again CRM_Dedupe_Merger::resetMergeStats($cacheKeyString); } $join = CRM_Dedupe_Merger::getJoinOnDedupeTable(); $where = "de.id IS NULL"; if ($context == 'conflicts') { $where .= " AND pn.is_selected = 1"; } $this->_mainContacts = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, $join, $where); if (empty($this->_mainContacts)) { if ($context == 'conflicts') { // if the current screen was intended to list only selected contacts, move back to full dupe list CRM_Utils_System::redirect(CRM_Utils_System::url(CRM_Utils_System::currentPath(), $urlQry . '&action=update')); } if ($gid) { $foundDupes = $this->get("dedupe_dupes_{$gid}"); if (!$foundDupes) { $foundDupes = CRM_Dedupe_Finder::dupesInGroup($rgid, $gid, $limit); } $this->set("dedupe_dupes_{$gid}", $foundDupes); } elseif (!empty($contactIds)) { $foundDupes = $this->get("search_dedupe_dupes_{$gid}"); if (!$foundDupes) { $foundDupes = CRM_Dedupe_Finder::dupes($rgid, $contactIds); } $this->set("search_dedupe_dupes_{$gid}", $foundDupes); } else { $foundDupes = $this->get('dedupe_dupes'); if (!$foundDupes) { $foundDupes = CRM_Dedupe_Finder::dupes($rgid, array(), TRUE, $limit); } $this->set('dedupe_dupes', $foundDupes); } if (!$foundDupes) { $ruleGroup = new CRM_Dedupe_BAO_RuleGroup(); $ruleGroup->id = $rgid; $ruleGroup->find(TRUE); $session = CRM_Core_Session::singleton(); $session->setStatus(ts('No possible duplicates were found using %1 rule.', array(1 => $ruleGroup->name)), ts('None Found'), 'info'); $url = CRM_Utils_System::url('civicrm/contact/deduperules', 'reset=1'); if ($context == 'search') { $url = $session->readUserContext(); } CRM_Utils_System::redirect($url); } else { $mainContacts = CRM_Dedupe_Finder::parseAndStoreDupePairs($foundDupes, $cacheKeyString); if ($cid) { $this->_cid = $cid; } if ($gid) { $this->_gid = $gid; } $this->_rgid = $rgid; $this->_mainContacts = $mainContacts; $session = CRM_Core_Session::singleton(); if ($this->_cid) { $session->pushUserContext(CRM_Utils_System::url('civicrm/contact/deduperules', $urlQry . "&action=update&cid={$this->_cid}")); } else { $session->pushUserContext(CRM_Utils_System::url('civicrm/contact/dedupefind', $urlQry . "&action=update")); } } } else { if ($cid) { $this->_cid = $cid; } if ($gid) { $this->_gid = $gid; } $this->_rgid = $rgid; } $this->assign('action', $this->action); $this->browse(); } else { $this->action = CRM_Core_Action::UPDATE; $this->edit($this->action); $this->assign('action', $this->action); } $this->assign('context', $context); // parent run return parent::run(); }
/** * Global validation rules for the form. * * @param array $fields * Posted values of the form. * * @param $files * @param $self * * @return array * list of errors to be posted back to the form */ public static function formRule($fields, $files, $self) { $errors = array(); if (!array_key_exists('savedMapping', $fields)) { $importKeys = array(); foreach ($fields['mapper'] as $mapperPart) { $importKeys[] = $mapperPart[0]; } // FIXME: should use the schema titles, not redeclare them $requiredFields = array('membership_contact_id' => ts('Contact ID'), 'membership_type_id' => ts('Membership Type'), 'membership_start_date' => ts('Membership Start Date')); $contactTypeId = $self->get('contactType'); $contactTypes = array(CRM_Import_Parser::CONTACT_INDIVIDUAL => 'Individual', CRM_Import_Parser::CONTACT_HOUSEHOLD => 'Household', CRM_Import_Parser::CONTACT_ORGANIZATION => 'Organization'); $params = array('used' => 'Unsupervised', 'contact_type' => $contactTypes[$contactTypeId]); list($ruleFields, $threshold) = CRM_Dedupe_BAO_RuleGroup::dedupeRuleFieldsWeight($params); $weightSum = 0; foreach ($importKeys as $key => $val) { if (array_key_exists($val, $ruleFields)) { $weightSum += $ruleFields[$val]; } } $fieldMessage = ''; foreach ($ruleFields as $field => $weight) { $fieldMessage .= ' ' . $field . '(weight ' . $weight . ')'; } foreach ($requiredFields as $field => $title) { if (!in_array($field, $importKeys)) { if ($field == 'membership_contact_id') { if (($weightSum >= $threshold || in_array('external_identifier', $importKeys)) && $self->_onDuplicate != CRM_Import_Parser::DUPLICATE_UPDATE || in_array('membership_id', $importKeys)) { continue; } else { if (!isset($errors['_qf_default'])) { $errors['_qf_default'] = ''; } $errors['_qf_default'] .= ts('Missing required contact matching fields.') . " {$fieldMessage} " . ts('(Sum of all weights should be greater than or equal to threshold: %1).', array(1 => $threshold)) . ' ' . ts('(OR Membership ID if update mode.)') . '<br />'; } } else { if (!isset($errors['_qf_default'])) { $errors['_qf_default'] = ''; } $errors['_qf_default'] .= ts('Missing required field: %1', array(1 => $title)) . '<br />'; } } } } if (!empty($fields['saveMapping'])) { $nameField = CRM_Utils_Array::value('saveMappingName', $fields); if (empty($nameField)) { $errors['saveMappingName'] = ts('Name is required to save Import Mapping'); } else { $mappingTypeId = CRM_Core_OptionGroup::getValue('mapping_type', 'Import Membership', 'name'); if (CRM_Core_BAO_Mapping::checkMapping($nameField, $mappingTypeId)) { $errors['saveMappingName'] = ts('Duplicate Import Membership Mapping Name'); } } } if (!empty($errors)) { if (!empty($errors['saveMappingName'])) { $_flag = 1; $assignError = new CRM_Core_Page(); $assignError->assign('mappingDetailsError', $_flag); } return $errors; } return TRUE; }
/** * global validation rules for the form * * @param array $fields posted values of the form * * @return array list of errors to be posted back to the form * @static * @access public */ static function formRule($fields, $files, $self) { $errors = array(); $fieldMessage = NULL; if (!array_key_exists('savedMapping', $fields)) { $importKeys = array(); foreach ($fields['mapper'] as $mapperPart) { $importKeys[] = $mapperPart[0]; } // FIXME: should use the schema titles, not redeclare them $requiredFields = array('participant_contact_id' => ts('Contact ID'), 'event_id' => ts('Event ID')); $contactTypeId = $self->get('contactType'); $contactTypes = array(CRM_Import_Parser::CONTACT_INDIVIDUAL => 'Individual', CRM_Import_Parser::CONTACT_HOUSEHOLD => 'Household', CRM_Import_Parser::CONTACT_ORGANIZATION => 'Organization'); $params = array('used' => 'Unsupervised', 'contact_type' => $contactTypes[$contactTypeId]); list($ruleFields, $threshold) = CRM_Dedupe_BAO_RuleGroup::dedupeRuleFieldsWeight($params); $weightSum = 0; foreach ($importKeys as $key => $val) { if (array_key_exists($val, $ruleFields)) { $weightSum += $ruleFields[$val]; } } foreach ($ruleFields as $field => $weight) { $fieldMessage .= ' ' . $field . '(weight ' . $weight . ')'; } foreach ($requiredFields as $field => $title) { if (!in_array($field, $importKeys)) { if ($field == 'participant_contact_id') { if ($weightSum >= $threshold || in_array('external_identifier', $importKeys) || in_array('participant_id', $importKeys)) { continue; } if ($self->_onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE) { $errors['_qf_default'] .= ts('Missing required field: Provide Particiapnt ID') . '<br />'; } else { $errors['_qf_default'] .= ts('Missing required contact matching fields.') . " {$fieldMessage} " . ts('(Sum of all weights should be greater than or equal to threshold: %1).', array(1 => $threshold)) . ' ' . ts('Or Provide Contact Id or External Identifier.') . '<br />'; } } elseif (!in_array('event_title', $importKeys)) { $errors['_qf_default'] .= ts('Missing required field: Provide %1 or %2', array(1 => $title, 2 => 'Event Title')) . '<br />'; } } } } if (CRM_Utils_Array::value('saveMapping', $fields)) { $nameField = CRM_Utils_Array::value('saveMappingName', $fields); if (empty($nameField)) { $errors['saveMappingName'] = ts('Name is required to save Import Mapping'); } else { $mappingTypeId = CRM_Core_OptionGroup::getValue('mapping_type', 'Import Participant', 'name'); if (CRM_Core_BAO_Mapping::checkMapping($nameField, $mappingTypeId)) { $errors['saveMappingName'] = ts('Duplicate Import Participant Mapping Name'); } } } //display Error if loaded mapping is not selected if (array_key_exists('loadMapping', $fields)) { $getMapName = CRM_Utils_Array::value('savedMapping', $fields); if (empty($getMapName)) { $errors['savedMapping'] = ts('Select saved mapping'); } } if (!empty($errors)) { if (!empty($errors['saveMappingName'])) { $_flag = 1; $assignError = new CRM_Core_Page(); $assignError->assign('mappingDetailsError', $_flag); } return $errors; } return TRUE; }
/** * Browse all rule groups. */ public function run() { $gid = CRM_Utils_Request::retrieve('gid', 'Positive', $this, FALSE, 0); $action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 0); $context = CRM_Utils_Request::retrieve('context', 'String', $this); $session = CRM_Core_Session::singleton(); $contactIds = $session->get('selectedSearchContactIds'); if ($context == 'search' || !empty($contactIds)) { $context = 'search'; $this->assign('backURL', $session->readUserContext()); } if ($action & CRM_Core_Action::RENEW) { // empty cache $rgid = CRM_Utils_Request::retrieve('rgid', 'Positive', $this, FALSE, 0); if ($rgid) { $contactType = CRM_Core_DAO::getFieldValue('CRM_Dedupe_DAO_RuleGroup', $rgid, 'contact_type'); $cacheKeyString = "merge {$contactType}"; $cacheKeyString .= $rgid ? "_{$rgid}" : '_0'; $cacheKeyString .= $gid ? "_{$gid}" : '_0'; CRM_Core_BAO_PrevNextCache::deleteItem(NULL, $cacheKeyString); } $urlQry = "reset=1&action=update&rgid={$rgid}"; if ($gid) { $urlQry .= "&gid={$gid}"; } CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/dedupefind', $urlQry)); } elseif ($action & CRM_Core_Action::MAP) { // do a batch merge if requested $rgid = CRM_Utils_Request::retrieve('rgid', 'Positive', $this, FALSE, 0); $result = CRM_Dedupe_Merger::batchMerge($rgid, $gid, 'safe', TRUE, 75); $skippedCount = CRM_Utils_Request::retrieve('skipped', 'Positive', $this, FALSE, 0); $skippedCount = $skippedCount + count($result['skipped']); $mergedCount = CRM_Utils_Request::retrieve('merged', 'Positive', $this, FALSE, 0); $mergedCount = $mergedCount + count($result['merged']); if (empty($result['merged']) && empty($result['skipped'])) { $message = ''; if ($mergedCount >= 1) { $message = ts("%1 pairs of duplicates were merged", array(1 => $mergedCount)); } if ($skippedCount >= 1) { $message = $message ? "{$message} and " : ''; $message .= ts("%1 pairs of duplicates were skipped due to conflict", array(1 => $skippedCount)); } $message .= ts(" during the batch merge process with safe mode."); CRM_Core_Session::setStatus($message, ts('Merge Complete'), 'success'); $urlQry = "reset=1&action=update&rgid={$rgid}"; if ($gid) { $urlQry .= "&gid={$gid}"; } CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/dedupefind', $urlQry)); } else { $urlQry = "reset=1&action=map&rgid={$rgid}"; if ($gid) { $urlQry .= "&gid={$gid}"; } $urlQry .= "&skipped={$skippedCount}&merged={$mergedCount}"; CRM_Utils_System::jsRedirect(CRM_Utils_System::url('civicrm/contact/dedupefind', $urlQry), ts('Batch Merge Task in progress'), ts('The batch merge task is still in progress. This page will be refreshed automatically.')); } } if ($action & CRM_Core_Action::UPDATE || $action & CRM_Core_Action::BROWSE) { $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, FALSE, 0); $rgid = CRM_Utils_Request::retrieve('rgid', 'Positive', $this, FALSE, 0); $this->action = CRM_Core_Action::UPDATE; //calculate the $contactType if ($rgid) { $contactType = CRM_Core_DAO::getFieldValue('CRM_Dedupe_DAO_RuleGroup', $rgid, 'contact_type'); } $sourceParams = 'snippet=4'; if ($gid) { $sourceParams .= "&gid={$gid}"; } if ($rgid) { $sourceParams .= "&rgid={$rgid}"; } if ($context == 'conflicts') { $sourceParams .= "&selected=1"; } $this->assign('sourceUrl', CRM_Utils_System::url('civicrm/ajax/dedupefind', $sourceParams, FALSE, NULL, FALSE)); //reload from cache table $cacheKeyString = "merge {$contactType}"; $cacheKeyString .= $rgid ? "_{$rgid}" : '_0'; $cacheKeyString .= $gid ? "_{$gid}" : '_0'; $stats = CRM_Dedupe_Merger::getMergeStatsMsg($cacheKeyString); if ($stats) { CRM_Core_Session::setStatus($stats); // reset so we not displaying same message again CRM_Dedupe_Merger::resetMergeStats($cacheKeyString); } $join = "LEFT JOIN civicrm_dedupe_exception de ON ( pn.entity_id1 = de.contact_id1 AND\n pn.entity_id2 = de.contact_id2 )"; $where = "de.id IS NULL"; if ($context == 'conflicts') { $where .= " AND pn.is_selected = 1"; } $this->_mainContacts = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, $join, $where); if (empty($this->_mainContacts)) { if ($context == 'conflicts') { // if the current screen was intended to list only selected contacts, move back to full dupe list $sourceParams = 'reset=1&action=update'; if ($gid) { $sourceParams .= "&gid={$gid}"; } if ($rgid) { $sourceParams .= "&rgid={$rgid}"; } CRM_Utils_System::redirect(CRM_Utils_System::url(CRM_Utils_System::currentPath(), $sourceParams)); } if ($gid) { $foundDupes = $this->get("dedupe_dupes_{$gid}"); if (!$foundDupes) { $foundDupes = CRM_Dedupe_Finder::dupesInGroup($rgid, $gid); } $this->set("dedupe_dupes_{$gid}", $foundDupes); } elseif (!empty($contactIds)) { $foundDupes = $this->get("search_dedupe_dupes_{$gid}"); if (!$foundDupes) { $foundDupes = CRM_Dedupe_Finder::dupes($rgid, $contactIds); } $this->get("search_dedupe_dupes_{$gid}", $foundDupes); } else { $foundDupes = $this->get('dedupe_dupes'); if (!$foundDupes) { $foundDupes = CRM_Dedupe_Finder::dupes($rgid); } $this->set('dedupe_dupes', $foundDupes); } if (!$foundDupes) { $ruleGroup = new CRM_Dedupe_BAO_RuleGroup(); $ruleGroup->id = $rgid; $ruleGroup->find(TRUE); $session = CRM_Core_Session::singleton(); $session->setStatus(ts('No possible duplicates were found using %1 rule.', array(1 => $ruleGroup->name)), ts('None Found'), 'info'); $url = CRM_Utils_System::url('civicrm/contact/deduperules', 'reset=1'); if ($context == 'search') { $url = $session->readUserContext(); } CRM_Utils_System::redirect($url); } else { $cids = array(); foreach ($foundDupes as $dupe) { $cids[$dupe[0]] = 1; $cids[$dupe[1]] = 1; } $cidString = implode(', ', array_keys($cids)); $sql = "SELECT id, display_name FROM civicrm_contact WHERE id IN ({$cidString}) ORDER BY sort_name"; $dao = new CRM_Core_DAO(); $dao->query($sql); $displayNames = array(); while ($dao->fetch()) { $displayNames[$dao->id] = $dao->display_name; } // FIXME: sort the contacts; $displayName // is already sort_name-sorted, so use that // (also, consider sorting by dupe count first) // lobo - change the sort to by threshold value // so the more likely dupes are sorted first $session = CRM_Core_Session::singleton(); $userId = $session->get('userID'); $mainContacts = $permission = array(); foreach ($foundDupes as $dupes) { $srcID = $dupes[0]; $dstID = $dupes[1]; if ($dstID == $userId) { $srcID = $dupes[1]; $dstID = $dupes[0]; } /*** * Eliminate this since it introduces 3 queries PER merge row * and hence is very expensive * CRM-8822 * if ( !array_key_exists( $srcID, $permission ) ) { * $permission[$srcID] = CRM_Contact_BAO_Contact_Permission::allow( $srcID, CRM_Core_Permission::EDIT ); * } * if ( !array_key_exists( $dstID, $permission ) ) { * $permission[$dstID] = CRM_Contact_BAO_Contact_Permission::allow( $dstID, CRM_Core_Permission::EDIT ); * } * * $canMerge = ( $permission[$dstID] && $permission[$srcID] ); * */ // we'll do permission checking during the merge process $canMerge = TRUE; $mainContacts[] = $row = array('srcID' => $srcID, 'srcName' => $displayNames[$srcID], 'dstID' => $dstID, 'dstName' => $displayNames[$dstID], 'weight' => $dupes[2], 'canMerge' => $canMerge); $data = CRM_Core_DAO::escapeString(serialize($row)); $values[] = " ( 'civicrm_contact', {$srcID}, {$dstID}, '{$cacheKeyString}', '{$data}' ) "; } if ($cid) { $this->_cid = $cid; } if ($gid) { $this->_gid = $gid; } $this->_rgid = $rgid; $this->_mainContacts = $mainContacts; CRM_Core_BAO_PrevNextCache::setItem($values); $session = CRM_Core_Session::singleton(); if ($this->_cid) { $session->pushUserContext(CRM_Utils_System::url('civicrm/contact/deduperules', "action=update&rgid={$this->_rgid}&gid={$this->_gid}&cid={$this->_cid}")); } else { $session->pushUserContext(CRM_Utils_System::url('civicrm/contact/dedupefind', "reset=1&action=update&rgid={$this->_rgid}")); } } } else { if ($cid) { $this->_cid = $cid; } if ($gid) { $this->_gid = $gid; } $this->_rgid = $rgid; } $this->assign('action', $this->action); $this->browse(); } else { $this->action = CRM_Core_Action::UPDATE; $this->edit($this->action); $this->assign('action', $this->action); } $this->assign('context', $context); // parent run return parent::run(); }
/** * Browse all rule groups * * @return void * @access public */ function run() { $gid = CRM_Utils_Request::retrieve('gid', 'Positive', $this, false, 0); $action = CRM_Utils_Request::retrieve('action', 'String', $this, false, 0); $context = CRM_Utils_Request::retrieve('context', 'String', $this); $session = CRM_Core_Session::singleton(); $contactIds = $session->get('selectedSearchContactIds'); if ($context == 'search' || !empty($contactIds)) { $context = 'search'; $this->assign('backURL', $session->readUserContext()); } if ($action & CRM_Core_Action::UPDATE || $action & CRM_Core_Action::BROWSE) { $cid = CRM_Utils_Request::retrieve('cid', 'Positive', $this, false, 0); $rgid = CRM_Utils_Request::retrieve('rgid', 'Positive', $this, false, 0); $this->action = CRM_Core_Action::UPDATE; if ($gid) { $foundDupes = $this->get("dedupe_dupes_{$gid}"); if (!$foundDupes) { $foundDupes = CRM_Dedupe_Finder::dupesInGroup($rgid, $gid); } $this->set("dedupe_dupes_{$gid}", $foundDupes); } else { if (!empty($contactIds)) { $foundDupes = $this->get("search_dedupe_dupes_{$gid}"); if (!$foundDupes) { $foundDupes = CRM_Dedupe_Finder::dupes($rgid, $contactIds); } $this->get("search_dedupe_dupes_{$gid}", $foundDupes); } else { $foundDupes = $this->get("dedupe_dupes"); if (!$foundDupes) { $foundDupes = CRM_Dedupe_Finder::dupes($rgid); } $this->set("dedupe_dupes", $foundDupes); } } if (!$foundDupes) { $ruleGroup = new CRM_Dedupe_BAO_RuleGroup(); $ruleGroup->id = $rgid; $ruleGroup->find(true); $session = CRM_Core_Session::singleton(); $session->setStatus("No possible duplicates were found using {$ruleGroup->name} rule."); $url = CRM_Utils_System::url('civicrm/contact/deduperules', "reset=1"); if ($context == 'search') { $url = $session->readUserContext(); } CRM_Utils_System::redirect($url); } else { $cids = array(); foreach ($foundDupes as $dupe) { $cids[$dupe[0]] = 1; $cids[$dupe[1]] = 1; } $cidString = implode(', ', array_keys($cids)); $sql = "SELECT id, display_name FROM civicrm_contact WHERE id IN ({$cidString}) ORDER BY sort_name"; $dao = new CRM_Core_DAO(); $dao->query($sql); $displayNames = array(); while ($dao->fetch()) { $displayNames[$dao->id] = $dao->display_name; } // FIXME: sort the contacts; $displayName // is already sort_name-sorted, so use that // (also, consider sorting by dupe count first) // lobo - change the sort to by threshold value // so the more likely dupes are sorted first $session = CRM_Core_Session::singleton(); $userId = $session->get('userID'); $mainContacts = array(); foreach ($foundDupes as $dupes) { $srcID = $dupes[0]; $dstID = $dupes[1]; if ($dstID == $userId) { $srcID = $dupes[1]; $dstID = $dupes[0]; } $canMerge = CRM_Contact_BAO_Contact_Permission::allow($dstID, CRM_Core_Permission::EDIT) && CRM_Contact_BAO_Contact_Permission::allow($srcID, CRM_Core_Permission::EDIT); $mainContacts[] = array('srcID' => $srcID, 'srcName' => $displayNames[$srcID], 'dstID' => $dstID, 'dstName' => $displayNames[$dstID], 'weight' => $dupes[2], 'canMerge' => $canMerge); } if ($cid) { $this->_cid = $cid; } if ($gid) { $this->_gid = $gid; } $this->_rgid = $rgid; $this->_mainContacts = $mainContacts; $session = CRM_Core_Session::singleton(); if ($this->_cid) { $session->pushUserContext(CRM_Utils_System::url('civicrm/contact/deduperules', "action=update&rgid={$this->_rgid}&gid={$this->_gid}&cid={$this->_cid}")); } else { $session->pushUserContext(CRM_Utils_System::url('civicrm/contact/dedupefind', "reset=1&action=update&rgid={$this->_rgid}")); } } $this->assign('action', $this->action); $this->browse(); } else { $this->action = CRM_Core_Action::UPDATE; $this->edit($this->action); $this->assign('action', $this->action); } $this->assign('context', $context); // parent run parent::run(); }
/** * To find fields related to a rule group. * * @param array contains the rule group property to identify rule group * * @return (rule field => weight) array and threshold associated to rule group * @access public */ function dedupeRuleFieldsWeight($params) { $rgBao = new CRM_Dedupe_BAO_RuleGroup(); $rgBao->level = $params['level']; $rgBao->contact_type = $params['contact_type']; $rgBao->is_default = 1; $rgBao->find(TRUE); $ruleBao = new CRM_Dedupe_BAO_Rule(); $ruleBao->dedupe_rule_group_id = $rgBao->id; $ruleBao->find(); $ruleFields = array(); while ($ruleBao->fetch()) { $ruleFields[$ruleBao->rule_field] = $ruleBao->rule_weight; } return array($ruleFields, $rgBao->threshold); }
/** * To find fields related to a rule group. * @param array contains the rule group property to identify rule group * * @return rule fields array associated to rule group * @access public */ function dedupeRuleFields($params) { require_once 'CRM/Dedupe/BAO/RuleGroup.php'; $rgBao = new CRM_Dedupe_BAO_RuleGroup(); $rgBao->level = $params['level']; $rgBao->contact_type = $params['contact_type']; $rgBao->is_default = 1; $rgBao->find(true); $ruleBao = new CRM_Dedupe_BAO_Rule(); $ruleBao->dedupe_rule_group_id = $rgBao->id; $ruleBao->find(); $ruleFields = array(); while ($ruleBao->fetch()) { $ruleFields[] = $ruleBao->rule_field; } return $ruleFields; }
/** * Get the cache key string for the merge action. * * @param int $rule_group_id * @param int $group_id * @param array $criteria * Additional criteria to narrow down the merge group. * Currently we are only supporting the key 'contact' within it. * * @param bool $checkPermissions * Respect the users permissions. * * @return string */ public static function getMergeCacheKeyString($rule_group_id, $group_id, $criteria = array(), $checkPermissions = TRUE) { $contactType = CRM_Dedupe_BAO_RuleGroup::getContactTypeForRuleGroup($rule_group_id); $cacheKeyString = "merge {$contactType}"; $cacheKeyString .= $rule_group_id ? "_{$rule_group_id}" : '_0'; $cacheKeyString .= $group_id ? "_{$group_id}" : '_0'; $cacheKeyString .= !empty($criteria) ? serialize($criteria) : '_0'; if ($checkPermissions) { $contactID = CRM_Core_Session::getLoggedInContactID(); if (!$contactID) { // Distinguish between no permission check & no logged in user. $contactID = 'null'; } $cacheKeyString .= '_' . $contactID; } else { $cacheKeyString .= '_0'; } return $cacheKeyString; }
static function buildDedupeRules() { $parent = CRM_Utils_Array::value('parentId', $_REQUEST); switch ($parent) { case 1: $contactType = 'Individual'; break; case 2: $contactType = 'Household'; break; case 4: $contactType = 'Organization'; break; } $dedupeRules = CRM_Dedupe_BAO_RuleGroup::getByType($contactType); CRM_Utils_JSON::output($dedupeRules); }
public static function buildDedupeRules() { $parent = CRM_Utils_Request::retrieve('parentId', 'Positive', CRM_Core_DAO::$_nullObject); switch ($parent) { case 1: $contactType = 'Individual'; break; case 2: $contactType = 'Household'; break; case 4: $contactType = 'Organization'; break; } $dedupeRules = CRM_Dedupe_BAO_RuleGroup::getByType($contactType); CRM_Utils_JSON::output($dedupeRules); }
/** * A hackish function needed to massage CRM_Contact_Form_$ctype::formRule() * object into a valid $params array for dedupe * * @param array $fields contact structure from formRule() * @param string $ctype contact type of the given contact * * @return array valid $params array for dedupe */ static function formatParams($fields, $ctype) { $flat = array(); CRM_Utils_Array::flatten($fields, $flat); $replace_these = array('individual_prefix' => 'prefix_id', 'individual_suffix' => 'suffix_id', 'gender' => 'gender_id'); //handle for individual_suffix, individual_prefix, gender foreach (array('individual_suffix', 'individual_prefix', 'gender') as $name) { if (CRM_Utils_Array::value($name, $fields)) { $flat[$replace_these[$name]] = $flat[$name]; unset($flat[$name]); } } // handle {birth,deceased}_date foreach (array('birth_date', 'deceased_date') as $date) { if (CRM_Utils_Array::value($date, $fields)) { $flat[$date] = $fields[$date]; if (is_array($flat[$date])) { $flat[$date] = CRM_Utils_Date::format($flat[$date]); } $flat[$date] = CRM_Utils_Date::processDate($flat[$date]); } } if (CRM_Utils_Array::value('contact_source', $flat)) { $flat['source'] = $flat['contact_source']; unset($flat['contact_source']); } // handle preferred_communication_method if (array_key_exists('preferred_communication_method', $fields)) { $methods = array_intersect($fields['preferred_communication_method'], array('1')); $methods = array_keys($methods); sort($methods); if ($methods) { $flat['preferred_communication_method'] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $methods) . CRM_Core_DAO::VALUE_SEPARATOR; } } // handle custom data $tree = CRM_Core_BAO_CustomGroup::getTree($ctype, CRM_Core_DAO::$_nullObject, NULL, -1); CRM_Core_BAO_CustomGroup::postProcess($tree, $fields, TRUE); foreach ($tree as $key => $cg) { if (!is_int($key)) { continue; } foreach ($cg['fields'] as $cf) { $flat[$cf['column_name']] = CRM_Utils_Array::value('data', $cf['customValue']); } } // if the key is dotted, keep just the last part of it foreach ($flat as $key => $value) { if (substr_count($key, '.')) { $last = array_pop(explode('.', $key)); // make sure the first occurence is kept, not the last if (!isset($flat[$last])) { $flat[$last] = $value; } unset($flat[$key]); } } // drop the -digit (and -Primary, for CRM-3902) postfixes (so event registration's $flat['email-5'] becomes $flat['email']) // FIXME: CRM-5026 should be fixed here; the below clobbers all address info; we should split off address fields and match // the -digit to civicrm_address.location_type_id and -Primary to civicrm_address.is_primary foreach ($flat as $key => $value) { $matches = array(); if (preg_match('/(.*)-(\\d+|Primary)$/', $key, $matches)) { $flat[$matches[1]] = $value; unset($flat[$key]); } } $params = array(); $supportedFields = CRM_Dedupe_BAO_RuleGroup::supportedFields($ctype); if (is_array($supportedFields)) { foreach ($supportedFields as $table => $fields) { if ($table == 'civicrm_address') { // for matching on civicrm_address fields, we also need the location_type_id $fields['location_type_id'] = ''; // FIXME: we also need to do some hacking for id and name fields, see CRM-3902’s comments $fixes = array('address_name' => 'name', 'country' => 'country_id', 'state_province' => 'state_province_id', 'county' => 'county_id'); foreach ($fixes as $orig => $target) { if (CRM_Utils_Array::value($orig, $flat)) { $params[$table][$target] = $flat[$orig]; } } } foreach ($fields as $field => $title) { if (CRM_Utils_Array::value($field, $flat)) { $params[$table][$field] = $flat[$field]; } } } } return $params; }
static function buildDedupeRules() { $parent = CRM_Utils_Array::value('parentId', $_POST); switch ($parent) { case 1: $contactType = 'Individual'; break; case 2: $contactType = 'Household'; break; case 4: $contactType = 'Organization'; break; } $dedupeRules = CRM_Dedupe_BAO_RuleGroup::getByType($contactType); echo json_encode($dedupeRules); CRM_Utils_System::civiExit(); }
/** * global validation rules for the form * * @param array $fields posted values of the form * * @param $files * @param $self * * @return array list of errors to be posted back to the form * @static * @access public */ static function formRule($fields, $files, $self) { $errors = array(); $fieldMessage = NULL; if (!array_key_exists('savedMapping', $fields)) { $importKeys = array(); foreach ($fields['mapper'] as $mapperPart) { $importKeys[] = $mapperPart[0]; } $contactTypeId = $self->get('contactType'); $contactTypes = array(CRM_Import_Parser::CONTACT_INDIVIDUAL => 'Individual', CRM_Import_Parser::CONTACT_HOUSEHOLD => 'Household', CRM_Import_Parser::CONTACT_ORGANIZATION => 'Organization'); $params = array('used' => 'Unsupervised', 'contact_type' => $contactTypes[$contactTypeId]); list($ruleFields, $threshold) = CRM_Dedupe_BAO_RuleGroup::dedupeRuleFieldsWeight($params); $weightSum = 0; foreach ($importKeys as $key => $val) { if (array_key_exists($val, $ruleFields)) { $weightSum += $ruleFields[$val]; } } foreach ($ruleFields as $field => $weight) { $fieldMessage .= ' ' . $field . '(weight ' . $weight . ')'; } } if (CRM_Utils_Array::value('saveMapping', $fields)) { $nameField = CRM_Utils_Array::value('saveMappingName', $fields); if (empty($nameField)) { $errors['saveMappingName'] = ts('Name is required to save Import Mapping'); } else { $mappingTypeId = CRM_Core_OptionGroup::getValue('mapping_type', $this->_mappingType, 'name'); if (CRM_Core_BAO_Mapping::checkMapping($nameField, $mappingTypeId)) { $errors['saveMappingName'] = ts('Duplicate ' . $this->_mappingType . 'Mapping Name'); } } } //display Error if loaded mapping is not selected if (array_key_exists('loadMapping', $fields)) { $getMapName = CRM_Utils_Array::value('savedMapping', $fields); if (empty($getMapName)) { $errors['savedMapping'] = ts('Select saved mapping'); } } if (!empty($errors)) { if (!empty($errors['saveMappingName'])) { $_flag = 1; $assignError = new CRM_Core_Page(); $assignError->assign('mappingDetailsError', $_flag); } return $errors; } return TRUE; }