/**
* @param $form
+ * @param array $params Parameters from the form.
*/
- public static function postProcess($form) {
- $params = $form->_params;
+ public static function postProcess($form, $params) {
if (!empty($form->_honor_block_is_active) && !empty($params['soft_credit_type_id'])) {
$honorId = NULL;
CRM_Utils_JSON::output(array('status' => ($status) ? $oper : $status));
}
+ /**
+ * Retrieve list of duplicate pairs from cache table.
+ */
public static function getDedupes() {
-
- $sEcho = CRM_Utils_Type::escape($_REQUEST['sEcho'], 'Integer');
- $offset = isset($_REQUEST['iDisplayStart']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayStart'], 'Integer') : 0;
- $rowCount = isset($_REQUEST['iDisplayLength']) ? CRM_Utils_Type::escape($_REQUEST['iDisplayLength'], 'Integer') : 25;
- $sort = 'sort_name';
- $sortOrder = isset($_REQUEST['sSortDir_0']) ? CRM_Utils_Type::escape($_REQUEST['sSortDir_0'], 'String') : 'asc';
-
- $gid = isset($_REQUEST['gid']) ? CRM_Utils_Type::escape($_REQUEST['gid'], 'Integer') : 0;
- $rgid = isset($_REQUEST['rgid']) ? CRM_Utils_Type::escape($_REQUEST['rgid'], 'Integer') : 0;
+ $offset = isset($_REQUEST['start']) ? CRM_Utils_Type::escape($_REQUEST['start'], 'Integer') : 0;
+ $rowCount = isset($_REQUEST['length']) ? CRM_Utils_Type::escape($_REQUEST['length'], 'Integer') : 25;
+
+ $gid = isset($_REQUEST['gid']) ? CRM_Utils_Type::escape($_REQUEST['gid'], 'Integer') : 0;
+ $rgid = isset($_REQUEST['rgid']) ? CRM_Utils_Type::escape($_REQUEST['rgid'], 'Integer') : 0;
+ $selected = isset($_REQUEST['selected']) ? CRM_Utils_Type::escape($_REQUEST['selected'], 'Integer') : 0;
+ if ($rowCount < 0) {
+ $rowCount = 0;
+ }
$contactType = '';
if ($rgid) {
$contactType = CRM_Core_DAO::getFieldValue('CRM_Dedupe_DAO_RuleGroup', $rgid, 'contact_type');
}
- $cacheKeyString = "merge {$contactType}_{$rgid}_{$gid}";
- $searchRows = array();
- $selectorElements = array('src', 'dst', 'weight', 'actions');
+ $cacheKeyString = "merge {$contactType}_{$rgid}_{$gid}";
+ $searchRows = array();
+ $selectorElements = array('is_selected', 'is_selected_input', 'src_image', 'src', 'src_email', 'src_street', 'src_postcode', 'dst_image', 'dst', 'dst_email', 'dst_street', 'dst_postcode', 'conflicts', 'weight', 'actions');
- $join = "LEFT JOIN civicrm_dedupe_exception de ON ( pn.entity_id1 = de.contact_id1 AND
- pn.entity_id2 = de.contact_id2 )";
- $where = "de.id IS NULL";
+ foreach ($_REQUEST['columns'] as $columnInfo) {
+ if (!empty($columnInfo['search']['value'])) {
+ ${$columnInfo['data']} = CRM_Utils_Type::escape($columnInfo['search']['value'], 'String');
+ }
+ }
+ $join = '';
+ $where = array();
+ $searchData = CRM_Utils_Array::value('search', $_REQUEST);
+ $searchData['value'] = CRM_Utils_Type::escape($searchData['value'], 'String');
+
+ if ($src || !empty($searchData['value'])) {
+ $src = $src ? $src : $searchData['value'];
+ $where[] = " cc1.display_name LIKE '%{$src}%'";
+ }
+ if ($dst || !empty($searchData['value'])) {
+ $dst = $dst ? $dst : $searchData['value'];
+ $where[] = " cc2.display_name LIKE '%{$dst}%'";
+ }
+ if ($src_email || !empty($searchData['value'])) {
+ $src_email = $src_email ? $src_email : $searchData['value'];
+ $where[] = " (ce1.is_primary = 1 AND ce1.email LIKE '%{$src_email}%')";
+ }
+ if ($dst_email || !empty($searchData['value'])) {
+ $dst_email = $dst_email ? $dst_email : $searchData['value'];
+ $where[] = " (ce2.is_primary = 1 AND ce2.email LIKE '%{$dst_email}%')";
+ }
+ if ($src_postcode || !empty($searchData['value'])) {
+ $src_postcode = $src_postcode ? $src_postcode : $searchData['value'];
+ $where[] = " (ca1.is_primary = 1 AND ca1.postal_code LIKE '%{$src_postcode}%')";
+ }
+ if ($dst_postcode || !empty($searchData['value'])) {
+ $dst_postcode = $dst_postcode ? $dst_postcode : $searchData['value'];
+ $where[] = " (ca2.is_primary = 1 AND ca2.postal_code LIKE '%{$dst_postcode}%')";
+ }
+ if ($src_street || !empty($searchData['value'])) {
+ $src_street = $src_street ? $src_street : $searchData['value'];
+ $where[] = " (ca1.is_primary = 1 AND ca1.street_address LIKE '%{$src_street}%')";
+ }
+ if ($dst_street || !empty($searchData['value'])) {
+ $dst_street = $dst_street ? $dst_street : $searchData['value'];
+ $where[] = " (ca2.is_primary = 1 AND ca2.street_address LIKE '%{$dst_street}%')";
+ }
+ if (!empty($searchData['value'])) {
+ $whereClause = ' ( ' . implode(' OR ', $where) . ' ) ';
+ }
+ else {
+ if (!empty($where)) {
+ $whereClause = implode(' AND ', $where);
+ }
+ }
+ $whereClause .= $whereClause ? ' AND de.id IS NULL' : ' de.id IS NULL';
- $iFilteredTotal = $iTotal = CRM_Core_BAO_PrevNextCache::getCount($cacheKeyString, $join, $where);
- $mainContacts = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, $join, $where, $offset, $rowCount);
+ if ($selected) {
+ $whereClause .= ' AND pn.is_selected = 1';
+ }
+ $join .= " LEFT JOIN civicrm_dedupe_exception de ON ( pn.entity_id1 = de.contact_id1 AND pn.entity_id2 = de.contact_id2 )";
+
+ $select = array(
+ 'cc1.contact_type' => 'src_contact_type',
+ 'cc1.display_name' => 'src_display_name',
+ 'cc1.contact_sub_type' => 'src_contact_sub_type',
+ 'cc2.contact_type' => 'dst_contact_type',
+ 'cc2.display_name' => 'dst_display_name',
+ 'cc2.contact_sub_type' => 'dst_contact_sub_type',
+ 'ce1.email' => 'src_email',
+ 'ce2.email' => 'dst_email',
+ 'ca1.postal_code' => 'src_postcode',
+ 'ca2.postal_code' => 'dst_postcode',
+ 'ca1.street_address' => 'src_street',
+ 'ca2.street_address' => 'dst_street',
+ );
+
+ if ($select) {
+ $join .= " INNER JOIN civicrm_contact cc1 ON cc1.id = pn.entity_id1";
+ $join .= " INNER JOIN civicrm_contact cc2 ON cc2.id = pn.entity_id2";
+ $join .= " LEFT JOIN civicrm_email ce1 ON (ce1.contact_id = pn.entity_id1 AND ce1.is_primary = 1 )";
+ $join .= " LEFT JOIN civicrm_email ce2 ON (ce2.contact_id = pn.entity_id2 AND ce2.is_primary = 1 )";
+ $join .= " LEFT JOIN civicrm_address ca1 ON (ca1.contact_id = pn.entity_id1 AND ca1.is_primary = 1 )";
+ $join .= " LEFT JOIN civicrm_address ca2 ON (ca2.contact_id = pn.entity_id2 AND ca2.is_primary = 1 )";
+ }
+ $iTotal = CRM_Core_BAO_PrevNextCache::getCount($cacheKeyString, $join, $whereClause);
+ foreach ($_REQUEST['order'] as $orderInfo) {
+ if (!empty($orderInfo['column'])) {
+ $orderColumnNumber = $orderInfo['column'];
+ $dir = $orderInfo['dir'];
+ }
+ }
+ $columnDetails = CRM_Utils_Array::value($orderColumnNumber, $_REQUEST['columns']);
+ if (!empty($columnDetails)) {
+ switch ($columnDetails['data']) {
+ case 'src':
+ $whereClause .= " ORDER BY cc1.display_name {$dir}";
+ break;
+
+ case 'src_email':
+ $whereClause .= " ORDER BY ce1.email {$dir}";
+ break;
+
+ case 'src_street':
+ $whereClause .= " ORDER BY ca1.street_address {$dir}";
+ break;
+
+ case 'src_postcode':
+ $whereClause .= " ORDER BY ca1.postal_code {$dir}";
+ break;
+
+ case 'dst':
+ $whereClause .= " ORDER BY cc2.display_name {$dir}";
+ break;
+
+ case 'dst_email':
+ $whereClause .= " ORDER BY ce2.email {$dir}";
+ break;
+
+ case 'dst_street':
+ $whereClause .= " ORDER BY ca2.street_address {$dir}";
+ break;
+
+ case 'dst_postcode':
+ $whereClause .= " ORDER BY ca2.postal_code {$dir}";
+ break;
+
+ default:
+ break;
+ }
+ }
- foreach ($mainContacts as $mainId => $main) {
- $searchRows[$mainId]['src'] = CRM_Utils_System::href($main['srcName'], 'civicrm/contact/view', "reset=1&cid={$main['srcID']}");
- $searchRows[$mainId]['dst'] = CRM_Utils_System::href($main['dstName'], 'civicrm/contact/view', "reset=1&cid={$main['dstID']}");
- $searchRows[$mainId]['weight'] = CRM_Utils_Array::value('weight', $main);
+ $dupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, $join, $whereClause, $offset, $rowCount, $select);
+ $iFilteredTotal = CRM_Core_DAO::singleValueQuery("SELECT FOUND_ROWS()");
+
+ $count = 0;
+ foreach ($dupePairs as $key => $pairInfo) {
+ $pair =& $pairInfo['data'];
+ $srcContactSubType = CRM_Utils_Array::value('src_contact_sub_type', $pairInfo);
+ $dstContactSubType = CRM_Utils_Array::value('dst_contact_sub_type', $pairInfo);
+ $srcTypeImage = CRM_Contact_BAO_Contact_Utils::getImage($srcContactSubType ?
+ $srcContactSubType : $pairInfo['src_contact_type'],
+ FALSE,
+ $pairInfo['entity_id1']
+ );
+ $dstTypeImage = CRM_Contact_BAO_Contact_Utils::getImage($dstContactSubType ?
+ $dstContactSubType : $pairInfo['dst_contact_type'],
+ FALSE,
+ $pairInfo['entity_id2']
+ );
- if (!empty($main['canMerge'])) {
- $mergeParams = "reset=1&cid={$main['srcID']}&oid={$main['dstID']}&action=update&rgid={$rgid}";
+ $searchRows[$count]['is_selected'] = $pairInfo['is_selected'];
+ $searchRows[$count]['is_selected_input'] = "<input type='checkbox' class='crm-dedupe-select' name='pnid_{$pairInfo['prevnext_id']}' value='{$pairInfo['is_selected']}' onclick='toggleDedupeSelect(this)'>";
+ $searchRows[$count]['src_image'] = $srcTypeImage;
+ $searchRows[$count]['src'] = CRM_Utils_System::href($pair['srcName'], 'civicrm/contact/view', "reset=1&cid={$pairInfo['entity_id1']}");
+ $searchRows[$count]['src_email'] = CRM_Utils_Array::value('src_email', $pairInfo);
+ $searchRows[$count]['src_street'] = CRM_Utils_Array::value('src_street', $pairInfo);
+ $searchRows[$count]['src_postcode'] = CRM_Utils_Array::value('src_postcode', $pairInfo);
+ $searchRows[$count]['dst_image'] = $dstTypeImage;
+ $searchRows[$count]['dst'] = CRM_Utils_System::href($pair['dstName'], 'civicrm/contact/view', "reset=1&cid={$pairInfo['entity_id2']}");
+ $searchRows[$count]['dst_email'] = CRM_Utils_Array::value('dst_email', $pairInfo);
+ $searchRows[$count]['dst_street'] = CRM_Utils_Array::value('dst_street', $pairInfo);
+ $searchRows[$count]['dst_postcode'] = CRM_Utils_Array::value('dst_postcode', $pairInfo);
+ $searchRows[$count]['conflicts'] = str_replace("',", "',<br/>", CRM_Utils_Array::value('conflicts', $pair));
+ $searchRows[$count]['weight'] = CRM_Utils_Array::value('weight', $pair);
+
+ if (!empty($pairInfo['data']['canMerge'])) {
+ $mergeParams = "reset=1&cid={$pairInfo['entity_id1']}&oid={$pairInfo['entity_id2']}&action=update&rgid={$rgid}";
if ($gid) {
$mergeParams .= "&gid={$gid}";
}
- $searchRows[$mainId]['actions'] = '<a class="action-item crm-hover-button" href="' . CRM_Utils_System::url('civicrm/contact/merge', $mergeParams) . '">' . ts('merge') . '</a>';
- $searchRows[$mainId]['actions'] .= "<a class='action-item crm-hover-button crm-notDuplicate' href='#' onClick=\"processDupes( {$main['srcID']}, {$main['dstID']}, 'dupe-nondupe', 'dupe-listing'); return false;\">" . ts('not a duplicate') . "</a>";
+ $searchRows[$count]['actions'] = "<a class='crm-dedupe-flip' href='#' data-pnid={$pairInfo['prevnext_id']}>" . ts('flip') . "</a> | ";
+ $searchRows[$count]['actions'] .= CRM_Utils_System::href(ts('merge'), 'civicrm/contact/merge', $mergeParams);
+ $searchRows[$count]['actions'] .= " | <a id='notDuplicate' href='#' onClick=\"processDupes( {$pairInfo['entity_id1']}, {$pairInfo['entity_id2']}, 'dupe-nondupe', 'dupe-listing'); return false;\">" . ts('not a duplicate') . "</a>";
}
else {
- $searchRows[$mainId]['actions'] = '<em>' . ts('Insufficient access rights - cannot merge') . '</em>';
+ $searchRows[$count]['actions'] = '<em>' . ts('Insufficient access rights - cannot merge') . '</em>';
}
+ $count++;
}
- CRM_Utils_System::setHttpHeader('Content-Type', 'application/json');
- echo CRM_Utils_JSON::encodeDataTableSelector($searchRows, $sEcho, $iTotal, $iFilteredTotal, $selectorElements);
-
- CRM_Utils_System::civiExit();
+ $dupePairs = array(
+ 'data' => $searchRows,
+ 'recordsTotal' => $iTotal,
+ 'recordsFiltered' => $iFilteredTotal,
+ );
+ CRM_Utils_JSON::output($dupePairs);
}
/**
CRM_Utils_JSON::output($paperSize);
}
+ /**
+ * Swap contacts in a dupe pair i.e main with duplicate contact.
+ */
+ public static function flipDupePairs($prevNextId = NULL) {
+ if (!$prevNextId) {
+ $prevNextId = $_REQUEST['pnid'];
+ }
+ $query = "
+ UPDATE civicrm_prevnext_cache cpc
+ INNER JOIN civicrm_prevnext_cache old on cpc.id = old.id
+ SET cpc.entity_id1 = cpc.entity_id2, cpc.entity_id2 = old.entity_id1 ";
+ if (is_array($prevNextId) && !CRM_Utils_Array::crmIsEmptyArray($prevNextId)) {
+ $prevNextId = implode(', ', $prevNextId);
+ $prevNextId = CRM_Utils_Type::escape($prevNextId, 'String');
+ $query .= "WHERE cpc.id IN ({$prevNextId}) AND cpc.is_selected = 1";
+ }
+ else {
+ $prevNextId = CRM_Utils_Type::escape($prevNextId, 'Positive');
+ $query .= "WHERE cpc.id = $prevNextId";
+ }
+ CRM_Core_DAO::executeQuery($query);
+ CRM_Utils_JSON::output();
+ }
+
/**
* Used to store selected contacts across multiple pages in advanced search.
*/
CRM_Utils_JSON::output($addressVal);
}
+ /**
+ * Mark dupe pairs as selected from un-selected state or vice-versa, in dupe cache table.
+ */
+ public static function toggleDedupeSelect() {
+ $rgid = CRM_Utils_Type::escape($_REQUEST['rgid'], 'Integer');
+ $gid = CRM_Utils_Type::escape($_REQUEST['gid'], 'Integer');
+ $pnid = $_REQUEST['pnid'];
+ $isSelected = CRM_Utils_Type::escape($_REQUEST['is_selected'], 'Boolean');
+
+ $contactType = CRM_Core_DAO::getFieldValue('CRM_Dedupe_DAO_RuleGroup', $rgid, 'contact_type');
+ $cacheKeyString = "merge $contactType";
+ $cacheKeyString .= $rgid ? "_{$rgid}" : '_0';
+ $cacheKeyString .= $gid ? "_{$gid}" : '_0';
+
+ $params = array(
+ 1 => array($isSelected, 'Boolean'),
+ 3 => array("$cacheKeyString%", 'String'), // using % to address rows with conflicts as well
+ );
+
+ //check pnid is_array or integer
+ $whereClause = NULL;
+ if (is_array($pnid) && !CRM_Utils_Array::crmIsEmptyArray($pnid)) {
+ $pnid = implode(', ', $pnid);
+ $pnid = CRM_Utils_Type::escape($pnid, 'String');
+ $whereClause = " id IN ( {$pnid} ) ";
+ }
+ else {
+ $pnid = CRM_Utils_Type::escape($pnid, 'Integer');
+ $whereClause = " id = %2";
+ $params[2] = array($pnid, 'Integer');
+ }
+
+ $sql = "UPDATE civicrm_prevnext_cache SET is_selected = %1 WHERE {$whereClause} AND cacheKey LIKE %3";
+ CRM_Core_DAO::executeQuery($sql, $params);
+
+ CRM_Utils_System::civiExit();
+ }
+
/**
* Retrieve contact relationships.
*/
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, TRUE);
+ $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']);
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));
$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
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) {
--- /dev/null
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.5 |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2014 |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM. |
+ | |
+ | CiviCRM is free software; you can copy, modify, and distribute it |
+ | under the terms of the GNU Affero General Public License |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
+ | |
+ | CiviCRM is distributed in the hope that it will be useful, but |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
+ | See the GNU Affero General Public License for more details. |
+ | |
+ | You should have received a copy of the GNU Affero General Public |
+ | License and the CiviCRM Licensing Exception along |
+ | with this program; if not, contact CiviCRM LLC |
+ | at info[AT]civicrm[DOT]org. If you have questions about the |
+ | GNU Affero General Public License or the licensing of CiviCRM, |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC (c) 2004-2014
+ * $Id$
+ *
+ */
+class CRM_Contact_Page_DedupeMerge extends CRM_Core_Page {
+
+ const BATCHLIMIT = 2;
+
+ /**
+ * Browse batch merges.
+ *
+ * @return void
+ * @access public
+ */
+ public function run() {
+ $runner = self::getRunner();
+ if ($runner) {
+ // Run Everything in the Queue via the Web.
+ $runner->runAllViaWeb();
+ }
+ else {
+ CRM_Core_Session::setStatus(ts('Nothing to merge.'));
+ }
+
+ // parent run
+ return parent::run();
+ }
+
+ /**
+ * Build a queue of tasks by dividing dupe pairs in batches.
+ */
+ public static function getRunner() {
+ $rgid = CRM_Utils_Request::retrieve('rgid', 'Positive', $this, FALSE, 0);
+ $gid = CRM_Utils_Request::retrieve('gid', 'Positive', $this, FALSE, 0);
+ $action = CRM_Utils_Request::retrieve('action', 'String', CRM_Core_DAO::$_nullObject);
+ $mode = CRM_Utils_Request::retrieve('mode', 'String', CRM_Core_DAO::$_nullObject, FALSE, 'safe');
+
+ $contactType = CRM_Core_DAO::getFieldValue('CRM_Dedupe_DAO_RuleGroup', $rgid, 'contact_type');
+ $cacheKeyString = "merge {$contactType}";
+ $cacheKeyString .= $rgid ? "_{$rgid}" : '_0';
+ $cacheKeyString .= $gid ? "_{$gid}" : '_0';
+
+ $urlQry = "reset=1&action=update&rgid={$rgid}";
+ $urlQry = $gid ? ($urlQry . "&gid={$gid}") : $urlQry;
+
+ if ($mode == 'aggressive' && !CRM_Core_Permission::check('force merge duplicate contacts')) {
+ CRM_Core_Session::setStatus(ts('You do not have permission to force merge duplicate contact records'), ts('Permission Denied'), 'error');
+ CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/dedupefind', $urlQry));
+ }
+ // Setup the Queue
+ $queue = CRM_Queue_Service::singleton()->create(array(
+ 'name' => $cacheKeyString,
+ 'type' => 'Sql',
+ 'reset' => TRUE,
+ ));
+
+ $where = NULL;
+ if ($action == CRM_Core_Action::MAP) {
+ $where = "pn.is_selected = 1";
+ $isSelected = 1;
+ }
+ else {
+ // else merge all (2)
+ $isSelected = 2;
+ }
+
+ $total = CRM_Core_BAO_PrevNextCache::getCount($cacheKeyString, NULL, $where);
+ if ($total <= 0) {
+ // Nothing to do.
+ CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/dedupefind', $urlQry));
+ }
+
+ // reset merge stats, so we compute new stats
+ CRM_Dedupe_Merger::resetMergeStats($cacheKeyString);
+
+ for ($i = 1; $i <= ceil($total / self::BATCHLIMIT); $i++) {
+ $task = new CRM_Queue_Task(
+ array('CRM_Contact_Page_DedupeMerge', 'callBatchMerge'),
+ array($rgid, $gid, $mode, TRUE, self::BATCHLIMIT, $isSelected),
+ "Processed " . $i * self::BATCHLIMIT . " pair of duplicates out of " . $total
+ );
+
+ // Add the Task to the Queue
+ $queue->createItem($task);
+ }
+
+ // Setup the Runner
+ $urlQry .= "&context=conflicts";
+ $runner = new CRM_Queue_Runner(array(
+ 'title' => ts('Merging Duplicates..'),
+ 'queue' => $queue,
+ 'errorMode' => CRM_Queue_Runner::ERROR_ABORT,
+ 'onEndUrl' => CRM_Utils_System::url('civicrm/contact/dedupefind', $urlQry, TRUE, NULL, FALSE),
+ ));
+
+ return $runner;
+ }
+
+ /**
+ * Carry out batch merges.
+ */
+ public static function callBatchMerge(CRM_Queue_TaskContext $ctx, $rgid, $gid = NULL, $mode = 'safe', $autoFlip = TRUE, $batchLimit = 1, $isSelected = 2) {
+ $result = CRM_Dedupe_Merger::batchMerge($rgid, $gid, $mode, $autoFlip, $batchLimit, $isSelected);
+
+ return CRM_Queue_Task::TASK_SUCCESS;
+ }
+
+}
}
}
+ /**
+ * Begin post processing.
+ *
+ * This function aims to start to bring together common postProcessing functions.
+ *
+ * Eventually these are also shared with the front end forms & may need to be moved to where they can also
+ * access this function.
+ */
+ protected function beginPostProcess() {
+ if (in_array('credit_card_exp_date', array_keys($this->_params))) {
+ $this->_params['year'] = CRM_Core_Payment_Form::getCreditCardExpirationYear($this->_params);
+ $this->_params['month'] = CRM_Core_Payment_Form::getCreditCardExpirationMonth($this->_params);
+ }
+
+ $this->_params['ip_address'] = CRM_Utils_System::ipAddress();
+ }
+
+
+ /**
+ * Add the billing address to the contact who paid.
+ *
+ * Note that this function works based on the presence or otherwise of billing fields & can be called regardless of
+ * whether they are 'expected' (due to assumptions about the payment processor type or the setting to collect billing
+ * for pay later.
+ */
+ protected function processBillingAddress() {
+ $fields = array();
+
+ $fields['email-Primary'] = 1;
+ $this->_params['email-5'] = $this->_params['email-Primary'] = $this->_contributorEmail;
+ // now set the values for the billing location.
+ foreach (array_keys($this->_fields) as $name) {
+ $fields[$name] = 1;
+ }
+
+ // also add location name to the array
+ $this->_params["address_name-{$this->_bltID}"] = CRM_Utils_Array::value('billing_first_name', $this->_params) . ' ' . CRM_Utils_Array::value('billing_middle_name', $this->_params) . ' ' . CRM_Utils_Array::value('billing_last_name', $this->_params);
+ $this->_params["address_name-{$this->_bltID}"] = trim($this->_params["address_name-{$this->_bltID}"]);
+
+ $fields["address_name-{$this->_bltID}"] = 1;
+
+ //ensure we don't over-write the payer's email with the member's email
+ if ($this->_contributorContactID == $this->_contactID) {
+ $fields["email-{$this->_bltID}"] = 1;
+ }
+
+ list($hasBillingField, $addressParams) = CRM_Contribute_BAO_Contribution::getPaymentProcessorReadyAddressParams($this->_params, $this->_bltID);
+ $nameFields = array('first_name', 'middle_name', 'last_name');
+
+ foreach ($nameFields as $name) {
+ $fields[$name] = 1;
+ if (array_key_exists("billing_$name", $this->_params)) {
+ $this->_params[$name] = $this->_params["billing_{$name}"];
+ $this->_params['preserveDBName'] = TRUE;
+ }
+ }
+
+ if ($hasBillingField) {
+ $addressParams = array_merge($this->_params, $addressParams);
+ //here we are setting up the billing contact - if different from the member they are already created
+ // but they will get billing details assigned
+ CRM_Contact_BAO_Contact::createProfileContact($addressParams, $fields,
+ $this->_contributorContactID, NULL, NULL,
+ CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactID, 'contact_type')
+ );
+ }
+ // Add additional parameters that the payment processors are used to receiving.
+ if (!empty($this->_params["billing_state_province_id-{$this->_bltID}"])) {
+ $this->_params["state_province-{$this->_bltID}"] = $this->_params["billing_state_province-{$this->_bltID}"] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($this->_params["billing_state_province_id-{$this->_bltID}"]);
+ }
+ if (!empty($this->_params["billing_country_id-{$this->_bltID}"])) {
+ $this->_params["country-{$this->_bltID}"] = $this->_params["billing_country-{$this->_bltID}"] = CRM_Core_PseudoConstant::countryIsoCode($this->_params["billing_country_id-{$this->_bltID}"]);
+ }
+ }
+
}
$submittedValues['source'] = ts('Submit Credit Card Payment by: %1', array(1 => $userSortName));
}
- $params = $this->_params = $submittedValues;
+ $params = $submittedValues;
+ $this->_params = array_merge($this->_params, $submittedValues);
// Mapping requiring documentation.
$this->_params['payment_processor'] = $submittedValues['payment_processor_id'];
$now = date('YmdHis');
- $fields = array();
// we need to retrieve email address
if ($this->_context == 'standalone' && !empty($submittedValues['is_email_receipt'])) {
$this->assign('displayName', $this->userDisplayName);
}
- // Set email for primary location.
- $fields['email-Primary'] = 1;
- $params['email-Primary'] = $this->userEmail;
-
- // now set the values for the billing location.
- foreach (array_keys($this->_fields) as $name) {
- $fields[$name] = 1;
- }
-
- // also add location name to the array
- $params["address_name-{$this->_bltID}"] = CRM_Utils_Array::value('billing_first_name', $params) . ' ' . CRM_Utils_Array::value('billing_middle_name', $params) . ' ' . CRM_Utils_Array::value('billing_last_name', $params);
-
- $params["address_name-{$this->_bltID}"] = trim($params["address_name-{$this->_bltID}"]);
- $fields["address_name-{$this->_bltID}"] = 1;
-
- $nameFields = array('first_name', 'middle_name', 'last_name');
- foreach ($nameFields as $name) {
- $fields[$name] = 1;
- if (array_key_exists("billing_$name", $params)) {
- $params[$name] = $params["billing_{$name}"];
- $params['preserveDBName'] = TRUE;
- }
- }
-
+ $this->_contributorEmail = $this->userEmail;
+ $this->_contributorContactID = $contactID;
+ $this->processBillingAddress();
if (!empty($params['source'])) {
unset($params['source']);
}
- CRM_Contact_BAO_Contact::createProfileContact($params, $fields,
- $contactID,
- NULL, NULL,
- CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
- $contactID,
- 'contact_type'
- )
- );
-
- // add all the additional payment params we need
- if (!empty($this->_params["billing_state_province_id-{$this->_bltID}"])) {
- $this->_params["state_province-{$this->_bltID}"] = $this->_params["billing_state_province-{$this->_bltID}"] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($this->_params["billing_state_province_id-{$this->_bltID}"]);
- }
- if (!empty($this->_params["billing_country_id-{$this->_bltID}"])) {
- $this->_params["country-{$this->_bltID}"] = $this->_params["billing_country-{$this->_bltID}"] = CRM_Core_PseudoConstant::countryIsoCode($this->_params["billing_country_id-{$this->_bltID}"]);
- }
-
- if (in_array('credit_card_exp_date', array_keys($this->_params))) {
- $this->_params['year'] = CRM_Core_Payment_Form::getCreditCardExpirationYear($this->_params);
- $this->_params['month'] = CRM_Core_Payment_Form::getCreditCardExpirationMonth($this->_params);
- }
- $this->_params['ip_address'] = CRM_Utils_System::ipAddress();
$this->_params['amount'] = $this->_params['total_amount'];
$this->_params['amount_level'] = 0;
$this->_params['description'] = ts("Contribution submitted by a staff person using contributor's credit card");
protected function submit($submittedValues, $action, $pledgePaymentID) {
$softParams = $softIDs = array();
$pId = $contribution = $isRelatedId = FALSE;
+ $this->_params = $submittedValues;
+ $this->beginPostProcess();
if (!empty($submittedValues['price_set_id']) && $action & CRM_Core_Action::UPDATE) {
$line = CRM_Price_BAO_LineItem::getLineItems($this->_id, 'contribution');
$contactID = $contributionParams['contact_id'];
$isEmailReceipt = !empty($form->_values['is_email_receipt']);
- // How do these vary from params? These are currently passed to
- // - custom data function....
- $formParams = $form->_params;
- $isSeparateMembershipPayment = empty($formParams['separate_membership_payment']) ? FALSE : TRUE;
- $pledgeID = empty($formParams['pledge_id']) ? NULL : $formParams['pledge_id'];
+ $isSeparateMembershipPayment = empty($params['separate_membership_payment']) ? FALSE : TRUE;
+ $pledgeID = empty($params['pledge_id']) ? NULL : $params['pledge_id'];
if (!$isSeparateMembershipPayment && !empty($form->_values['pledge_block_id']) &&
- (!empty($formParams['is_pledge']) || $pledgeID)) {
+ (!empty($params['is_pledge']) || $pledgeID)) {
$isPledge = TRUE;
}
else {
}
//CRM-13981, processing honor contact into soft-credit contribution
- CRM_Contact_Form_ProfileContact::postProcess($form);
+ CRM_Contact_Form_ProfileContact::postProcess($form, $params);
// process soft credit / pcp pages
CRM_Contribute_Form_Contribution_Confirm::processPcpSoft($params, $contribution);
if ($pledgeID) {
//when user doing pledge payments.
//update the schedule when payment(s) are made
- foreach ($form->_params['pledge_amount'] as $paymentId => $dontCare) {
+ foreach ($params['pledge_amount'] as $paymentId => $dontCare) {
$scheduledAmount = CRM_Core_DAO::getFieldValue(
'CRM_Pledge_DAO_PledgePayment',
$paymentId,
}
if ($online && $contribution) {
- CRM_Core_BAO_CustomValueTable::postProcess($form->_params,
+ CRM_Core_BAO_CustomValueTable::postProcess($params,
'civicrm_contribution',
$contribution->id,
'Contribution'
$this->set('invoiceID', $invoiceID);
$params['invoiceID'] = $invoiceID;
$params['description'] = ts('Online Contribution') . ': ' . (($this->_pcpInfo['title']) ? $this->_pcpInfo['title'] : $this->_values['title']);
-
+ $params['button'] = $this->controller->getButtonName();
// required only if is_monetary and valid positive amount
if ($this->_values['is_monetary'] &&
is_array($this->_paymentProcessor) &&
}
- /**
- * Handle pre approval for processors.
- *
- * This fits with the flow where a pre-approval is done and then confirmed in the next stage when confirm is hit.
- *
- * This applies to processors that
- * @param array $params
- */
- protected function handlePreApproval(&$params) {
- try {
- $payment = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
- $params['component'] = 'contribute';
- $result = $payment->doPreApproval($params);
- }
- catch (\Civi\Payment\Exception\PaymentProcessorException $e) {
- CRM_Core_Error::displaySessionError($e->getMessage());
- CRM_Utils_System::redirect($params['cancelURL']);
- }
-
- $this->set('pre_approval_parameters', $result['pre_approval_parameters']);
- if (!empty($result['redirect_url'])) {
- CRM_Utils_System::redirect($result['redirect_url']);
- }
- }
-
/**
* Process confirm function and pass browser to the thank you page.
*/
default:
break;
}
- $set[$field['column_name']] = "%{$count}";
- $params[$count] = array($value, $type);
- $count++;
+ if (strtolower($value) === "null") {
+ // when unsetting a value to null, we don't need to validate the type
+ // https://projectllr.atlassian.net/browse/VGQBMP-20
+ $set[$field['column_name']] = $value;
+ }
+ else {
+ $set[$field['column_name']] = "%{$count}";
+ $params[$count] = array($value, $type);
+ $count++;
+ }
}
if (!empty($set)) {
if (isset($cacheKey)) {
$sql .= " AND cacheKey LIKE %4";
- $params[4] = array("{$cacheKey}%", 'String');
+ $params[4] = array("{$cacheKey}%", 'String'); // used % to address any row with conflict-cacheKey e.g "merge Individual_8_0_conflicts"
}
CRM_Core_DAO::executeQuery($sql, $params);
}
+ public static function markConflict($id1, $id2, $cacheKey, $conflicts) {
+ if (empty($cacheKey) || empty($conflicts)) {
+ return FALSE;
+ }
+
+ $sql = "SELECT pn.*
+ FROM civicrm_prevnext_cache pn
+ WHERE
+ ((pn.entity_id1 = %1 AND pn.entity_id2 = %2) OR (pn.entity_id1 = %2 AND pn.entity_id2 = %1)) AND
+ (cacheKey = %3 OR cacheKey = %4)";
+ $params = array(
+ 1 => array($id1, 'Integer'),
+ 2 => array($id2, 'Integer'),
+ 3 => array("{$cacheKey}", 'String'),
+ 4 => array("{$cacheKey}_conflicts", 'String'),
+ );
+ $pncFind = CRM_Core_DAO::executeQuery($sql, $params);
+
+ while ($pncFind->fetch()) {
+ $data = $pncFind->data;
+ if (!empty($data)) {
+ $data = unserialize($data);
+ $data['conflicts'] = implode(",", array_values($conflicts));
+
+ $pncUp = new CRM_Core_DAO_PrevNextCache();
+ $pncUp->id = $pncFind->id;
+ if ($pncUp->find(TRUE)) {
+ $pncUp->data = serialize($data);
+ $pncUp->cacheKey = "{$cacheKey}_conflicts";
+ $pncUp->save();
+ }
+ }
+ }
+ return TRUE;
+ }
+
/**
* @param $cacheKey
* @param NULL $join
*
* @return array
*/
- public static function retrieve($cacheKey, $join = NULL, $where = NULL, $offset = 0, $rowCount = 0) {
+ public static function retrieve($cacheKey, $join = NULL, $where = NULL, $offset = 0, $rowCount = 0, $select = array()) {
+ $selectString = 'pn.*';
+ if (!empty($select)) {
+ $aliasArray = array();
+ foreach ($select as $column => $alias) {
+ $aliasArray[] = $column . ' as ' . $alias;
+ }
+ $selectString .= " , " . implode(' , ', $aliasArray);
+ }
$query = "
-SELECT data
+SELECT SQL_CALC_FOUND_ROWS {$selectString}
FROM civicrm_prevnext_cache pn
{$join}
-WHERE cacheKey = %1
+WHERE (pn.cacheKey = %1 OR pn.cacheKey = %2)
";
- $params = array(1 => array($cacheKey, 'String'));
+ $params = array(
+ 1 => array($cacheKey, 'String'),
+ 2 => array("{$cacheKey}_conflicts", 'String'),
+ );
if ($where) {
$query .= " AND {$where}";
$dao = CRM_Core_DAO::executeQuery($query, $params);
- $main = array();
+ $main = array();
+ $count = 0;
while ($dao->fetch()) {
if (self::is_serialized($dao->data)) {
- $main[] = unserialize($dao->data);
+ $main[$count] = unserialize($dao->data);
}
else {
- $main[] = $dao->data;
+ $main[$count] = $dao->data;
+ }
+
+ if (!empty($select)) {
+ $extraData = array();
+ foreach ($select as $dfield => $sfield) {
+ $extraData[$sfield] = $dao->$sfield;
+ }
+ $main[$count] = array(
+ 'prevnext_id' => $dao->id,
+ 'is_selected' => $dao->is_selected,
+ 'entity_id1' => $dao->entity_id1,
+ 'entity_id2' => $dao->entity_id2,
+ 'data' => $main[$count],
+ );
+ $main[$count] = array_merge($main[$count], $extraData);
}
+ $count++;
}
return $main;
$query = "
SELECT COUNT(*) FROM civicrm_prevnext_cache pn
{$join}
-WHERE cacheKey $op %1
+WHERE (pn.cacheKey $op %1 OR pn.cacheKey $op %2)
";
if ($where) {
$query .= " AND {$where}";
}
- $params = array(1 => array($cacheKey, 'String'));
+ $params = array(
+ 1 => array($cacheKey, 'String'),
+ 2 => array("{$cacheKey}_conflicts", 'String'),
+ );
return (int) CRM_Core_DAO::singleValueQuery($query, $params, TRUE, FALSE);
}
$this->assign('paymentProcessorID', $this->_paymentProcessorID);
}
+ /**
+ * Handle pre approval for processors.
+ *
+ * This fits with the flow where a pre-approval is done and then confirmed in the next stage when confirm is hit.
+ *
+ * This function is shared between contribution & event forms & this is their common class.
+ *
+ * However, this should be seen as an in-progress refactor, the end goal being to also align the
+ * backoffice forms that action payments.
+ *
+ * @param array $params
+ */
+ protected function handlePreApproval(&$params) {
+ try {
+ $payment = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
+ $params['component'] = 'contribute';
+ $result = $payment->doPreApproval($params);
+ if (empty($result)) {
+ // This could happen, for example, when paypal looks at the button value & decides it is not paypal express.
+ return;
+ }
+ }
+ catch (\Civi\Payment\Exception\PaymentProcessorException $e) {
+ CRM_Core_Error::displaySessionError($e->getMessage());
+ CRM_Utils_System::redirect($params['cancelURL']);
+ }
+
+ $this->set('pre_approval_parameters', $result['pre_approval_parameters']);
+ if (!empty($result['redirect_url'])) {
+ CRM_Utils_System::redirect($result['redirect_url']);
+ }
+ }
+
/**
* Setter function for options.
*
protected $_paymentProcessor;
+ /**
+ * Base url of the calling form.
+ *
+ * This is used for processors that need to return the browser back to the CiviCRM site.
+ *
+ * @var string
+ */
+ protected $baseReturnUrl;
+
+ /**
+ * Set Base return URL.
+ *
+ * @param string $url
+ * Url of site to return browser to.
+ */
+ public function setBaseReturnUrl($url) {
+ $this->baseReturnUrl = $url;
+ }
+
/**
* Opportunity for the payment processor to override the entire form build.
*
/**
* Get base url dependent on component.
*
- * @return string|void
+ * (or preferably set it using the setter function).
+ *
+ * @return string
*/
protected function getBaseReturnUrl() {
+ if ($this->baseReturnUrl) {
+ return $this->baseReturnUrl;
+ }
if ($this->_component == 'event') {
$baseURL = 'civicrm/event/register';
}
+--------------------------------------------------------------------+
*/
+use Civi\Payment\Exception\PaymentProcessorException;
+
/**
*
* @package CRM
* @return bool
*/
protected function supportsPreApproval() {
- if ($this->_processorName == ts('PayPal Express')) {
+ if ($this->_processorName == ts('PayPal Express') || $this->_processorName == ts('PayPal Pro')) {
return TRUE;
}
return FALSE;
* @return array
*/
public function getPreApprovalDetails($storedDetails) {
- return $this->getExpressCheckoutDetails($storedDetails['token']);
+ return empty($storedDetails['token']) ? array() : $this->getExpressCheckoutDetails($storedDetails['token']);
}
/**
* @throws \Civi\Payment\Exception\PaymentProcessorException
*/
public function doPayment(&$params, $component = 'contribute') {
- if ($this->_paymentProcessor['payment_processor_type'] != 'PayPal_Express') {
+ if ($this->_paymentProcessor['payment_processor_type'] != 'PayPal_Express'
+ && (!empty($params['credit_card_number']) && empty($params['token']))
+ ) {
return parent::doPayment($params, $component);
}
$this->_component = $component;
* - redirect_url (if set the browser will be redirected to this.
*/
public function doPreApproval(&$params) {
+ if (!isset($params['button']) || !stristr($params['button'], 'express')) {
+ return array();
+ }
$this->_component = $params['component'];
$token = $this->setExpressCheckOut($params);
return array(
$prefix . ts('merge duplicate contacts'),
ts('Delete Contacts must also be granted in order for this to work.'),
),
+ 'force merge duplicate contacts' => array(
+ $prefix . ts('force merge duplicate contacts'),
+ ts('Delete Contacts must also be granted in order for this to work.'),
+ ),
'view debug output' => array(
$prefix . ts('view debug output'),
ts('View results of debug and backtrace'),
<page_callback>CRM_Contact_Page_AJAX::getDedupes</page_callback>
<access_arguments>merge duplicate contacts</access_arguments>
</item>
+<item>
+ <path>civicrm/contact/dedupemerge</path>
+ <title>Batch Merge Duplicate Contacts</title>
+ <page_callback>CRM_Contact_Page_DedupeMerge</page_callback>
+ <access_arguments>merge duplicate contacts</access_arguments>
+</item>
<item>
<path>civicrm/dedupe/exception</path>
<title>Dedupe Exceptions</title>
<page_callback>CRM_Contact_Page_AJAX::selectUnselectContacts</page_callback>
<access_arguments>access CiviCRM</access_arguments>
</item>
+<item>
+ <path>civicrm/ajax/toggleDedupeSelect</path>
+ <page_callback>CRM_Contact_Page_AJAX::toggleDedupeSelect</page_callback>
+ <access_arguments>merge duplicate contacts</access_arguments>
+</item>
+<item>
+ <path>civicrm/ajax/flipDupePairs</path>
+ <page_callback>CRM_Contact_Page_AJAX::flipDupePairs</page_callback>
+ <access_arguments>merge duplicate contacts</access_arguments>
+</item>
<item>
<path>civicrm/activity/sms/add</path>
<path_arguments>action=add</path_arguments>
$this->assign('cdType', FALSE);
$this->assign('cgCount', $this->_groupCount);
- // Carry qf key, since this form is not inheriting core form (unclear is still the case).
- if ($qfKey = CRM_Utils_Request::retrieve('qfKey', 'String')) {
- $this->assign('qfKey', $qfKey);
- }
if (!is_array($this->_subType) && strstr($this->_subType, CRM_Core_DAO::VALUE_SEPARATOR)) {
$this->_subType = str_replace(CRM_Core_DAO::VALUE_SEPARATOR, ',', trim($this->_subType, CRM_Core_DAO::VALUE_SEPARATOR));
}
CRM_Custom_Form_CustomData::setGroupTree($this, $this->_subType, NULL, $this->_groupID);
+
+ $this->assign('suppressForm', TRUE);
+ $this->controller->_generateQFKey = FALSE;
}
/**
* Does a force merge otherwise.
* @param bool $autoFlip to let api decide which contact to retain and which to delete.
* Wether to let api decide which contact to retain and which to delete.
- * @param bool $redirectForPerformance
+ * @param int $batchLimit number of merges to carry out in one batch.
+ * @param int $isSelected if records with is_selected column needs to be processed.
*
* @return array|bool
*/
- public static function batchMerge($rgid, $gid = NULL, $mode = 'safe', $autoFlip = TRUE, $redirectForPerformance = FALSE) {
+ public static function batchMerge($rgid, $gid = NULL, $mode = 'safe', $autoFlip = TRUE, $batchLimit = 1, $isSelected = 2) {
$contactType = CRM_Core_DAO::getFieldValue('CRM_Dedupe_DAO_RuleGroup', $rgid, 'contact_type');
$cacheKeyString = "merge {$contactType}";
$cacheKeyString .= $rgid ? "_{$rgid}" : '_0';
$join = "LEFT JOIN civicrm_dedupe_exception de ON ( pn.entity_id1 = de.contact_id1 AND
pn.entity_id2 = de.contact_id2 )";
- $limit = $redirectForPerformance ? 75 : 1;
- $where = "de.id IS NULL LIMIT {$limit}";
+ $where = "de.id IS NULL";
+ if ($isSelected === 0 || $isSelected === 1) {
+ $where .= " AND pn.is_selected = {$isSelected}";
+ }// else consider all dupe pairs
+ $where .= " LIMIT {$batchLimit}";
+
+ $redirectForPerformance = ($batchLimit > 1) ? TRUE : FALSE;
$dupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, $join, $where);
- if (empty($dupePairs) && !$redirectForPerformance) {
+ if (empty($dupePairs) && !$redirectForPerformance && $isSelected == 2) {
// If we haven't found any dupes, probably cache is empty.
// Try filling cache and give another try.
CRM_Core_BAO_PrevNextCache::refillCache($rgid, $gid, $cacheKeyString);
return CRM_Dedupe_Merger::merge($dupePairs, $cacheParams, $mode, $autoFlip, $redirectForPerformance);
}
+ public static function updateMergeStats($cacheKeyString, $result = array()) {
+ // gather latest stats
+ $merged = count($result['merged']);
+ $skipped = count($result['skipped']);
+
+ if ($merged <= 0 && $skipped <= 0) {
+ return;
+ }
+
+ // get previous stats
+ $previousStats = CRM_Core_BAO_PrevNextCache::retrieve("{$cacheKeyString}_stats");
+ if (!empty($previousStats)) {
+ if ($previousStats[0]['merged']) {
+ $merged = $merged + $previousStats[0]['merged'];
+ }
+ if ($previousStats[0]['skipped']) {
+ $skipped = $skipped + $previousStats[0]['skipped'];
+ }
+ }
+
+ // delete old stats
+ CRM_Dedupe_Merger::resetMergeStats($cacheKeyString);
+
+ // store the updated stats
+ $data = array(
+ 'merged' => $merged,
+ 'skipped' => $skipped,
+ );
+ $data = CRM_Core_DAO::escapeString(serialize($data));
+
+ $values = array();
+ $values[] = " ( 'civicrm_contact', 0, 0, '{$cacheKeyString}_stats', '$data' ) ";
+ CRM_Core_BAO_PrevNextCache::setItem($values);
+ }
+
+ public static function resetMergeStats($cacheKeyString) {
+ return CRM_Core_BAO_PrevNextCache::deleteItem(NULL, "{$cacheKeyString}_stats");
+ }
+
+ public static function getMergeStats($cacheKeyString) {
+ $stats = CRM_Core_BAO_PrevNextCache::retrieve("{$cacheKeyString}_stats");
+ if (!empty($stats)) {
+ $stats = $stats[0];
+ }
+ return $stats;
+ }
+
+ public static function getMergeStatsMsg($cacheKeyString) {
+ $msg = '';
+ $stats = CRM_Dedupe_Merger::getMergeStats($cacheKeyString);
+ if (!empty($stats['merged'])) {
+ $msg = "{$stats['merged']} " . ts(' Contact(s) were merged. ');
+ }
+ if (!empty($stats['skipped'])) {
+ $msg .= $stats['skipped'] . ts(' Contact(s) were skipped.');
+ }
+ return $msg;
+ }
+
/**
* Merge given set of contacts. Performs core operation.
*
$migrationInfo['rows'] = &$rowsElementsAndInfo['rows'];
// go ahead with merge if there is no conflict
- if (!CRM_Dedupe_Merger::skipMerge($mainId, $otherId, $migrationInfo, $mode)) {
+ $conflicts = array();
+ if (!CRM_Dedupe_Merger::skipMerge($mainId, $otherId, $migrationInfo, $mode, $conflicts)) {
CRM_Dedupe_Merger::moveAllBelongings($mainId, $otherId, $migrationInfo);
$resultStats['merged'][] = array('main_id' => $mainId, 'other_id' => $otherId);
}
$resultStats['skipped'][] = array('main_id' => $mainId, 'other_id' => $otherId);
}
- // delete entry from PrevNextCache table so we don't consider the pair next time
- // pair may have been flipped, so make sure we delete using both orders
- CRM_Core_BAO_PrevNextCache::deletePair($mainId, $otherId, $cacheKeyString);
- CRM_Core_BAO_PrevNextCache::deletePair($otherId, $mainId, $cacheKeyString);
+ // store any conflicts
+ if (!empty($conflicts)) {
+ foreach ($conflicts as $key => $dnc) {
+ $conflicts[$key] = "{$migrationInfo['rows'][$key]['title']}: '{$migrationInfo['rows'][$key]['main']}' vs. '{$migrationInfo['rows'][$key]['other']}'";
+ }
+ CRM_Core_BAO_PrevNextCache::markConflict($mainId, $otherId, $cacheKeyString, $conflicts);
+ }
+ else {
+ // delete entry from PrevNextCache table so we don't consider the pair next time
+ // pair may have been flipped, so make sure we delete using both orders
+ CRM_Core_BAO_PrevNextCache::deletePair($mainId, $otherId, $cacheKeyString, TRUE);
+ }
CRM_Core_DAO::freeResult();
unset($rowsElementsAndInfo, $migrationInfo);
unset($dupePairs);
}
}
+
+ CRM_Dedupe_Merger::updateMergeStats($cacheKeyString, $resultStats);
return $resultStats;
}
*
* @return bool
*/
- public static function skipMerge($mainId, $otherId, &$migrationInfo, $mode = 'safe') {
- $conflicts = array();
+ public static function skipMerge($mainId, $otherId, &$migrationInfo, $mode = 'safe', &$conflicts = array()) {
+ //$conflicts = array();
$migrationData = array(
'old_migration_info' => $migrationInfo,
'mode' => $mode,
// particular field or not
if (!empty($migrationInfo['rows'][$key]['main'])) {
// if main also has a value its a conflict
- if ($mode == 'safe') {
- // note it down & lets wait for response from the hook.
- // For no response skip this merge
- $conflicts[$key] = NULL;
- }
- elseif ($mode == 'aggressive') {
- // let the main-field be overwritten
- continue;
- }
+
+ // note it down & lets wait for response from the hook.
+ // For no response $mode will decide if to skip this merge
+ $conflicts[$key] = NULL;
}
}
elseif (substr($key, 0, 14) == 'move_location_' and $val != NULL) {
// try insert address at new available loc-type
$migrationInfo['location'][$fieldName][$fieldCount]['locTypeId'] = $newTypeId;
}
- elseif ($mode == 'safe') {
+ else {
// note it down & lets wait for response from the hook.
- // For no response skip this merge
+ // For no response $mode will decide if to skip this merge
$conflicts[$key] = NULL;
}
- elseif ($mode == 'aggressive') {
- // let the loc-type-id be same as that of other-contact & go ahead
- // with merge assuming aggressive mode
- continue;
- }
}
}
elseif ($migrationInfo['rows'][$key]['main'] == $migrationInfo['rows'][$key]['other']) {
// merge happens with new values filled in here. For a particular field / row not to be merged
// field should be unset from fields_in_conflict.
$migrationData['fields_in_conflict'] = $conflicts;
+ $migrationData['merge_mode'] = $mode;
CRM_Utils_Hook::merge('batch', $migrationData, $mainId, $otherId);
$conflicts = $migrationData['fields_in_conflict'];
+ // allow hook to override / manipulate migrationInfo as well
+ $migrationInfo = $migrationData['old_migration_info'];
if (!empty($conflicts)) {
foreach ($conflicts as $key => $val) {
if ($val === NULL and $mode == 'safe') {
- // un-resolved conflicts still present. Lets skip this merge.
+ // un-resolved conflicts still present. Lets skip this merge after saving the conflict / reason.
return TRUE;
}
else {
$migrationInfo[$key] = $val;
}
}
+ // if there are conflicts and mode is aggressive, allow hooks to decide if to skip merges
+ if (array_key_exists('skip_merge', $migrationData)) {
+ return (bool) $migrationData['skip_merge'];
+ }
}
return FALSE;
}
if (is_array($this->_paymentProcessor)) {
$payment = $this->_paymentProcessor['object'];
}
+ if (!empty($this->_paymentProcessor) && $this->_paymentProcessor['object']->supports('preApproval')) {
+ $preApprovalParams = $this->_paymentProcessor['object']->getPreApprovalDetails($this->get('pre_approval_parameters'));
+ $value = array_merge($value, $preApprovalParams);
+ }
$result = NULL;
if (!empty($value['is_pay_later']) ||
}
/**
- * Check if profiles are complete when event registration occurs(CRM-9587)
+ * Check if profiles are complete when event registration occurs(CRM-9587).
+ *
+ * @param array $fields
+ * @param array $errors
+ * @param int $eventId
*/
public static function checkProfileComplete($fields, &$errors, $eventId) {
$email = '';
if (is_array($this->_paymentProcessor)) {
$payment = $this->_paymentProcessor['object'];
+ $payment->setBaseReturnUrl('civicrm/event/register');
}
// default mode is direct
$this->set('contributeMode', 'direct');
$params['invoiceID'] = $invoiceID;
}
$this->_params = $this->get('params');
+ // Set the button so we know what
+ $params['button'] = $this->controller->getButtonName();
if (!empty($this->_params) && is_array($this->_params)) {
$this->_params[0] = $params;
}
$this->_params[] = $params;
}
$this->set('params', $this->_params);
-
if ($this->_paymentProcessor &&
- $this->_paymentProcessor['billing_mode'] & CRM_Core_Payment::BILLING_MODE_BUTTON
+ $this->_paymentProcessor['object']->supports('preApproval')
+ && !$this->_allowWaitlist &&
+ !$this->_requireApproval
) {
- //get the button name
- $buttonName = $this->controller->getButtonName();
- if (in_array($buttonName,
- array(
- $this->_expressButtonName,
- $this->_expressButtonName . '_x',
- $this->_expressButtonName . '_y',
- )
- ) && empty($params['is_pay_later']) &&
- !$this->_allowWaitlist &&
- !$this->_requireApproval
- ) {
- $this->set('contributeMode', 'express');
- // Send Event Name & Id in Params
- $params['eventName'] = $this->_values['event']['title'];
- $params['eventId'] = $this->_values['event']['id'];
-
- $params['cancelURL'] = CRM_Utils_System::url('civicrm/event/register',
- "_qf_Register_display=1&qfKey={$this->controller->_key}",
- TRUE, NULL, FALSE
- );
- if (CRM_Utils_Array::value('additional_participants', $params, FALSE)) {
- $urlArgs = "_qf_Participant_1_display=1&rfp=1&qfKey={$this->controller->_key}";
- }
- else {
- $urlArgs = "_qf_Confirm_display=1&rfp=1&qfKey={$this->controller->_key}";
- }
- $params['returnURL'] = CRM_Utils_System::url('civicrm/event/register',
- $urlArgs,
- TRUE, NULL, FALSE
- );
- $params['invoiceID'] = $invoiceID;
+ $this->handlePreApproval($params);
- $params['component'] = 'event';
- $token = $payment->doPreApproval($params);
- if (is_a($token, 'CRM_Core_Error')) {
- CRM_Core_Error::displaySessionError($token);
- CRM_Utils_System::redirect($params['cancelURL']);
- }
+ $this->set('contributeMode', 'express');
- $this->set('token', $token);
+ // Send Event Name & Id in Params
+ $params['eventName'] = $this->_values['event']['title'];
+ $params['eventId'] = $this->_values['event']['id'];
- $paymentURL = $this->_paymentProcessor['url_site'] . "/cgi-bin/webscr?cmd=_express-checkout&token=$token";
+ $params['cancelURL'] = CRM_Utils_System::url('civicrm/event/register',
+ "_qf_Register_display=1&qfKey={$this->controller->_key}",
+ TRUE, NULL, FALSE
+ );
+ if (CRM_Utils_Array::value('additional_participants', $params, FALSE)) {
+ $urlArgs = "_qf_Participant_1_display=1&rfp=1&qfKey={$this->controller->_key}";
+ }
+ else {
+ $urlArgs = "_qf_Confirm_display=1&rfp=1&qfKey={$this->controller->_key}";
+ }
+ $params['returnURL'] = CRM_Utils_System::url('civicrm/event/register',
+ $urlArgs,
+ TRUE, NULL, FALSE
+ );
+ $params['invoiceID'] = $invoiceID;
- CRM_Utils_System::redirect($paymentURL);
+ $params['component'] = 'event';
+ $token = $payment->doPreApproval($params);
+ if (is_a($token, 'CRM_Core_Error')) {
+ CRM_Core_Error::displaySessionError($token);
+ CRM_Utils_System::redirect($params['cancelURL']);
}
+
+ $this->set('token', $token);
+
+ $paymentURL = $this->_paymentProcessor['url_site'] . "/cgi-bin/webscr?cmd=_express-checkout&token=$token";
+ CRM_Utils_System::redirect($paymentURL);
}
elseif ($this->_paymentProcessor &&
$this->_paymentProcessor['billing_mode'] & CRM_Core_Payment::BILLING_MODE_NOTIFY
) {
$this->set('contributeMode', 'notify');
}
- }
- else {
- $session = CRM_Core_Session::singleton();
- $params['description'] = ts('Online Event Registration') . ' ' . $this->_values['event']['title'];
+ else {
+ $params['description'] = ts('Online Event Registration') . ' ' . $this->_values['event']['title'];
- $this->_params = array();
- $this->_params[] = $params;
- $this->set('params', $this->_params);
+ $this->_params = array();
+ $this->_params[] = $params;
+ $this->set('params', $this->_params);
- if (
- empty($params['additional_participants'])
- && !$this->_values['event']['is_confirm_enabled'] // CRM-11182 - Optional confirmation screen
- ) {
- self::processRegistration($this->_params);
+ if (
+ empty($params['additional_participants'])
+ && !$this->_values['event']['is_confirm_enabled'] // CRM-11182 - Optional confirmation screen
+ ) {
+ self::processRegistration($this->_params);
+ }
}
}
* @param array $params
* Form values.
* @param int $contactID
- *
- * @return void
*/
public function processRegistration($params, $contactID = NULL) {
$session = CRM_Core_Session::singleton();
$primaryContactId, $isTest, TRUE
);
- //lets carry all paticipant params w/ values.
+ //lets carry all participant params w/ values.
foreach ($additionalIDs as $participantID => $contactId) {
$participantNum = NULL;
if ($participantID == $registerByID) {
*
* @param array $fields
* The input form values(anonymous user).
- * @param array $self
+ * @param CRM_Event_Form_Registration_Register $self
* Event data.
* @param bool $isAdditional
* Treat isAdditional participants a bit differently.
$contributionSoftParams = CRM_Utils_Array::value('soft_credit', $params);
$recordContribution = array(
'contact_id',
+ 'fee_amount',
'total_amount',
'receive_date',
'financial_type_id',
*/
public $_priceSet;
+ /**
+ * Values submitted to the form, processed along the way.
+ *
+ * @var array
+ */
+ protected $_params = array();
+
public function preProcess() {
// Check for edit permission.
if (!CRM_Core_Permission::checkActionPermission('CiviMember', $this->_action)) {
return $formValues;
}
+ /**
+ * Assign billing name to the template.
+ */
+ protected function assignBillingName() {
+ $name = '';
+ if (!empty($this->_params['billing_first_name'])) {
+ $name = $this->_params['billing_first_name'];
+ }
+
+ if (!empty($this->_params['billing_middle_name'])) {
+ $name .= " {$this->_params['billing_middle_name']}";
+ }
+
+ if (!empty($this->_params['billing_last_name'])) {
+ $name .= " {$this->_params['billing_last_name']}";
+ }
+ $this->assign('billingName', $name);
+ }
+
+ /**
+ * Wrapper function for unit tests.
+ *
+ * @param array $formValues
+ */
+ public function testSubmit($formValues) {
+ $this->_memType = $formValues['membership_type_id'][1];
+ $this->_params = $formValues;
+ $this->submit();
+ }
+
}
$this->assign('is_pay_later', TRUE);
}
if ($this->_mode) {
- // set default country from config if no country set
- $config = CRM_Core_Config::singleton();
- if (empty($defaults["billing_country_id-{$this->_bltID}"])) {
- $defaults["billing_country_id-{$this->_bltID}"] = $config->defaultContactCountry;
- }
-
- if (empty($defaults["billing_state_province_id-{$this->_bltID}"])) {
- $defaults["billing_state_province_id-{$this->_bltID}"] = $config->defaultContactStateProvince;
- }
-
- $billingDefaults = $this->getProfileDefaults('Billing', $this->_contactID);
- $defaults = array_merge($defaults, $billingDefaults);
-
+ $defaults = $this->getBillingDefaults($defaults);
// hack to simplify credit card entry for testing
// $defaults['credit_card_type'] = 'Visa';
// $defaults['credit_card_number'] = '4807731747657838';
// get the submitted form values.
$this->_params = $this->controller->exportValues($this->_name);
- $this->submit($this->_params);
+ $this->submit();
$this->setUserContext();
}
$form->assign('customValues', $customValues);
if ($form->_mode) {
- $name = '';
- if (!empty($form->_params['billing_first_name'])) {
- $name = $form->_params['billing_first_name'];
- }
-
- if (!empty($form->_params['billing_middle_name'])) {
- $name .= " {$form->_params['billing_middle_name']}";
- }
-
- if (!empty($form->_params['billing_last_name'])) {
- $name .= " {$form->_params['billing_last_name']}";
- }
-
- $form->assign('billingName', $name);
-
// assign the address formatted up for display
$addressParts = array(
"street_address-{$form->_bltID}",
*
* This is also accessed by unit tests.
*
- * @param array $formValues
- *
* @return array
*/
- public function submit($formValues) {
+ public function submit() {
$isTest = ($this->_mode == 'test') ? 1 : 0;
-
+ $this->storeContactFields($this->_params);
+ $formValues = $this->_params;
$joinDate = $startDate = $endDate = NULL;
$membershipTypes = $membership = $calcDate = array();
$membershipType = NULL;
$mailSend = FALSE;
$formValues = $this->setPriceSetParameters($formValues);
-
$params = $softParams = $ids = array();
$allMemberStatus = CRM_Member_PseudoConstant::membershipStatus();
$allContributionStatus = CRM_Contribute_PseudoConstant::contributionStatus();
+ $this->processBillingAddress();
if ($this->_id) {
$ids['membership'] = $params['id'] = $this->_id;
}
}
- $this->storeContactFields($formValues);
-
$params['contact_id'] = $this->_contactID;
$fields = array(
//get the payment processor id as per mode.
$params['payment_processor_id'] = $formValues['payment_processor_id'] = $this->_paymentProcessor['id'];
-
- $now = date('YmdHis');
- $fields = array();
-
- // set email for primary location.
- $fields['email-Primary'] = 1;
- $formValues['email-5'] = $formValues['email-Primary'] = $this->_memberEmail;
- $params['register_date'] = $now;
-
- // now set the values for the billing location.
- foreach ($this->_fields as $name => $dontCare) {
- $fields[$name] = 1;
- }
-
- // also add location name to the array
- $formValues["address_name-{$this->_bltID}"] = CRM_Utils_Array::value('billing_first_name', $formValues) . ' ' . CRM_Utils_Array::value('billing_middle_name', $formValues) . ' ' . CRM_Utils_Array::value('billing_last_name', $formValues);
-
- $formValues["address_name-{$this->_bltID}"] = trim($formValues["address_name-{$this->_bltID}"]);
-
- $fields["address_name-{$this->_bltID}"] = 1;
- //ensure we don't over-write the payer's email with the member's email
- if ($this->_contributorContactID == $this->_contactID) {
- $fields["email-{$this->_bltID}"] = 1;
- }
-
- $nameFields = array('first_name', 'middle_name', 'last_name');
-
- foreach ($nameFields as $name) {
- $fields[$name] = 1;
- if (array_key_exists("billing_$name", $formValues)) {
- $formValues[$name] = $formValues["billing_{$name}"];
- $formValues['preserveDBName'] = TRUE;
- }
- }
- if ($this->_contributorContactID == $this->_contactID) {
- //see CRM-12869 for discussion of why we don't do this for separate payee payments
- CRM_Contact_BAO_Contact::createProfileContact($formValues, $fields,
- $this->_contributorContactID, NULL, NULL,
- CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactID, 'contact_type')
- );
- }
+ $params['register_date'] = date('YmdHis');
// add all the additional payment params we need
$formValues["state_province-{$this->_bltID}"] = $formValues["billing_state_province-{$this->_bltID}"]
}
}
}
+ $now = date('YmdHis');
$params['receive_date'] = $now;
$params['invoice_id'] = $formValues['invoiceID'];
$params['contribution_source'] = ts('%1 Membership Signup: Credit card or direct debit (by %2)',
if (!empty($softParams) && empty($paymentParams['is_recur'])) {
$membershipParams['soft_credit'] = $softParams;
}
+ if (isset($result['fee_amount'])) {
+ $membershipParams['fee_amount'] = $result['fee_amount'];
+ }
// This is required to trigger the recording of the membership contribution in the
// CRM_Member_BAO_Membership::Create function.
// @todo stop setting this & 'teach' the create function to respond to something
// although at some point we should switch in the templates.
$formValues['receipt_text_signup'] = $formValues['receipt_text'];
// send email receipt
+ $this->assignBillingName();
$mailSend = self::emailReceipt($this, $formValues, $membership);
}
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2015
- * $Id$
- *
*/
/**
$this->assign('member_is_test', CRM_Utils_Array::value('member_is_test', $defaults));
if ($this->_mode) {
- // set default country from config if no country set
- $config = CRM_Core_Config::singleton();
- if (empty($defaults["billing_country_id-{$this->_bltID}"])) {
- $defaults["billing_country_id-{$this->_bltID}"] = $config->defaultContactCountry;
- }
-
- if (empty($defaults["billing_state_province_id-{$this->_bltID}"])) {
- $defaults["billing_state_province_id-{$this->_bltID}"] = $config->defaultContactStateProvince;
- }
-
- $billingDefaults = $this->getProfileDefaults('Billing', $this->_contactID);
- $defaults = array_merge($defaults, $billingDefaults);
-
+ $defaults = $this->getBillingDefaults($defaults);
}
return $defaults;
}
/**
* Process the renewal form.
- *
- *
- * @return void
*/
public function postProcess() {
// get the submitted form values.
$now = CRM_Utils_Date::getToday(NULL, 'YmdHis');
$this->convertDateFieldsToMySQL($this->_params);
$this->assign('receive_date', $this->_params['receive_date']);
- $this->processBillingAddress($now);
+ $this->processBillingAddress();
list($userName) = CRM_Contact_BAO_Contact_Location::getEmailDetails(CRM_Core_Session::singleton()->get('userID'));
$this->_params['total_amount'] = CRM_Utils_Array::value('total_amount', $this->_params,
CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $this->_memType, 'minimum_fee')
$li['financial_type_id'] = $submittedFinancialType;
}
}
- $this->_params['total_amount'] = CRM_Utils_Array::value('amount', $this->_params);
+
if (!empty($lineItem)) {
$this->_params['lineItems'] = $lineItem;
$this->_params['processPriceSet'] = TRUE;
}
/**
- * Wrapper function for unit tests.
+ * @param $defaults
*
- * @param array $formValues
+ * @return array
*/
- public function testSubmit($formValues) {
- $this->_memType = $formValues['membership_type_id'][1];
- $this->_params = $formValues;
- $this->submit($formValues);
- }
-
- protected function assignBillingName() {
- $name = '';
- if (!empty($this->_params['billing_first_name'])) {
- $name = $this->_params['billing_first_name'];
+ protected function getBillingDefaults($defaults) {
+ // set default country from config if no country set
+ $config = CRM_Core_Config::singleton();
+ if (empty($defaults["billing_country_id-{$this->_bltID}"])) {
+ $defaults["billing_country_id-{$this->_bltID}"] = $config->defaultContactCountry;
}
- if (!empty($this->_params['billing_middle_name'])) {
- $name .= " {$this->_params['billing_middle_name']}";
+ if (empty($defaults["billing_state_province_id-{$this->_bltID}"])) {
+ $defaults["billing_state_province_id-{$this->_bltID}"] = $config->defaultContactStateProvince;
}
- if (!empty($this->_params['billing_last_name'])) {
- $name .= " {$this->_params['billing_last_name']}";
- }
- $this->assign('billingName', $name);
- }
-
- /**
- * Add the billing address to the contact who paid.
- */
- protected function processBillingAddress() {
- $fields = array();
-
- // set email for primary location.
- $fields['email-Primary'] = 1;
- $this->_params['email-5'] = $this->_params['email-Primary'] = $this->_contributorEmail;
-
- // also add location name to the array
- $this->_params["address_name-{$this->_bltID}"] = CRM_Utils_Array::value('billing_first_name', $this->_params) . ' ' . CRM_Utils_Array::value('billing_middle_name', $this->_params) . ' ' . CRM_Utils_Array::value('billing_last_name', $this->_params);
-
- $this->_params["address_name-{$this->_bltID}"] = trim($this->_params["address_name-{$this->_bltID}"]);
-
- $fields["address_name-{$this->_bltID}"] = 1;
- $fields["email-{$this->_bltID}"] = 1;
-
- list($hasBillingField, $addressParams) = CRM_Contribute_BAO_Contribution::getPaymentProcessorReadyAddressParams($this->_params, $this->_bltID);
-
- $addressParams['preserveDBName'] = TRUE;
- if ($hasBillingField) {
- $addressParams = array_merge($this->_params, $addressParams);
- //here we are setting up the billing contact - if different from the member they are already created
- // but they will get billing details assigned
- CRM_Contact_BAO_Contact::createProfileContact($addressParams, $fields,
- $this->_contributorContactID, NULL, NULL,
- CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactID, 'contact_type')
- );
- }
+ $billingDefaults = $this->getProfileDefaults('Billing', $this->_contactID);
+ return array_merge($defaults, $billingDefaults);
}
}
*}
{if $action eq 2 || $action eq 16}
<div class="form-item">
- <table class='pagerDisplay'>
+ <div class="crm-accordion-wrapper crm-search_filters-accordion">
+ <div class="crm-accordion-header">
+ {ts}Filter Contacts{/ts}</a>
+ </div><!-- /.crm-accordion-header -->
+ <div class="crm-accordion-body">
+ <table class="no-border form-layout-compressed" id="searchOptions" style="width:100%;">
+ <tr>
+ <td class="crm-contact-form-block-contact1">
+ <label for="contact1">{ts}Contact 1{/ts}</label><br />
+ <input type="text" placeholder="Search Contact1" search-column="2" />
+ </td>
+ <td class="crm-contact-form-block-contact2">
+ <label for="contact2">{ts}Contact 2{/ts}</label><br />
+ <input type="text" placeholder="Search Contact2" search-column="4" />
+ </td>
+ <td class="crm-contact-form-block-email1">
+ <label for="email1">{ts}Email 1{/ts}</label><br />
+ <input type="text" placeholder="Search Email1" search-column="5" />
+ </td>
+ <td class="crm-contact-form-block-email2">
+ <label for="email2">{ts}Email 2{/ts}</label><br />
+ <input type="text" placeholder="Search Email2" search-column="6" />
+ </td>
+ </tr>
+ <tr>
+ <td class="crm-contact-form-block-street-address1">
+ <label for="street-adddress1">{ts}Street Address 1{/ts}</label><br />
+ <input type="text" placeholder="Search Street Address1" search-column="7" />
+ </td>
+ <td class="crm-contact-form-block-street-address2">
+ <label for="street-adddress2">{ts}Street Address 2{/ts}</label><br />
+ <input type="text" placeholder="Search Street Address2" search-column="8" />
+ </td>
+ <td class="crm-contact-form-block-postcode1">
+ <label for="postcode1">{ts}Postcode 1{/ts}</label><br />
+ <input type="text" placeholder="Search Postcode1" search-column="9" />
+ </td>
+ <td class="crm-contact-form-block-postcode2">
+ <label for="postcode2">{ts}Postcode 2{/ts}</label><br />
+ <input type="text" placeholder="Search Postcode2" search-column="10" />
+ </td>
+ </tr>
+ </table>
+ </div><!-- /.crm-accordion-body -->
+ </div><!-- /.crm-accordion-wrapper -->
+ <div>
+ Show / Hide columns:
+ <input type='checkbox' id ='steet-address' class='toggle-vis' data-column-main="7" data-column-dupe="8" >
+ <label for="steet-address">{ts}Street Address{/ts} </label>
+ <input type='checkbox' id ='post-code' class='toggle-vis' data-column-main="9" data-column-dupe="10" >
+ <label for="post-code">{ts}Post Code{/ts} </label>
+ <input type='checkbox' id ='conflicts' class='toggle-vis' data-column-main="11" >
+ <label for="conflicts">{ts}Conflicts{/ts} </label>
+ <input type='checkbox' id ='threshold' class='toggle-vis' data-column-main="12" >
+ <label for="threshold">{ts}Threshold{/ts} </label>
+ </div><br/>
+ <span id="dupePairs_length_selection">
+ <input type='checkbox' id ='crm-dedupe-display-selection' name="display-selection">
+ <label for="display-selection">{ts}Within Selections{/ts} </label>
+ </span>
+
+ <table id="dupePairs"
+ class="nestedActivitySelector crm-ajax-table"
+ cellspacing="0"
+ width="100%"
+ data-page-length="10",
+ data-searching='true',
+ data-dom='flrtip',
+ data-order='[]',
+ data-column-defs='{literal}[{"targets": [0,1,3,13], "orderable":false}, {"targets": [7,8,9,10,11,12], "visible":false}]{/literal}'>
<thead>
- <tr class="columnheader"><th id="nosort">{ts}Contact{/ts} 1</th><th id="nosort">{ts}Contact{/ts} 2 ({ts}Duplicate{/ts})</th><th id="nosort">{ts}Threshold{/ts}</th><th id="nosort"> </th></tr>
+ <tr class="columnheader">
+ <th data-data="is_selected_input" class="crm-dedupe-selection"><input type="checkbox" value="0" name="pnid_all" class="crm-dedupe-select-all"></th>
+ <th data-data="src_image" class="crm-empty"> </th>
+ <th data-data="src" class="crm-contact">{ts}Contact{/ts} 1</th>
+ <th data-data="dst_image" class="crm-empty"> </th>
+ <th data-data="dst" class="crm-contact-duplicate">{ts}Contact{/ts} 2 ({ts}Duplicate{/ts})</th>
+ <th data-data="src_email" class="crm-contact">{ts}Email{/ts} 1</th>
+ <th data-data="dst_email" class="crm-contact-duplicate">{ts}Email{/ts} 2 ({ts}Duplicate{/ts})</th>
+ <th data-data="src_street" class="crm-contact">{ts}Street Address{/ts} 1</th>
+ <th data-data="dst_street" class="crm-contact-duplicate">{ts}Street Address{/ts} 2 ({ts}Duplicate{/ts})</th>
+ <th data-data="src_postcode" class="crm-contact">{ts}Postcode{/ts} 1</th>
+ <th data-data="dst_postcode" class="crm-contact-duplicate">{ts}Postcode{/ts} 2 ({ts}Duplicate{/ts})</th>
+ <th data-data="conflicts" class="crm-contact-conflicts">{ts}Conflicts{/ts}</th>
+ <th data-data="weight" class="crm-threshold">{ts}Threshold{/ts}</th>
+ <th data-data="actions" class="crm-empty"> </th>
+ </tr>
</thead>
+ <tbody>
+ </tbody>
</table>
- {include file="CRM/common/jsortable.tpl" sourceUrl=$sourceUrl useAjax=1 }
{if $cid}
<table style="width: 45%; float: left; margin: 10px;">
<tr class="columnheader"><th colspan="2">{ts 1=$main_contacts[$cid]}Merge %1 with{/ts}</th></tr>
{if $context eq 'search'}
{crmButton href=$backURL icon="close"}{ts}Done{/ts}{/crmButton}
+{elseif $context eq 'conflicts'}
+ {if call_user_func(array('CRM_Core_Permission','check'), 'force merge duplicate contacts')}
+ {if $gid}
+ {capture assign=backURL}{crmURL p="civicrm/contact/dedupemerge" q="reset=1&rgid=`$rgid`&gid=`$gid`&action=map&mode=aggressive" a=1}{/capture}
+ {else}
+ {capture assign=backURL}{crmURL p="civicrm/contact/dedupemerge" q="reset=1&rgid=`$rgid`&action=map&mode=aggressive" a=1}{/capture}
+ {/if}
+ <a href="{$backURL}" title="{ts}Force Merge Selected Duplicates{/ts}" onclick="return confirm('{ts escape="js"}This will run the batch merge process on the selected duplicates. The operation will run in force merge mode - all selected duplicates will be merged into main contacts even in case of any conflicts. Click OK to proceed if you are sure you wish to run this operation.{/ts}');" class="button"><span><div class="icon ui-icon-script"></div>{ts}Force Merge Selected Duplicates{/ts}</span></a>
+
+ {if $gid}
+ {capture assign=backURL}{crmURL p="civicrm/contact/dedupemerge" q="reset=1&rgid=`$rgid`&gid=`$gid`&action=map" a=1}{/capture}
+ {else}
+ {capture assign=backURL}{crmURL p="civicrm/contact/dedupemerge" q="reset=1&rgid=`$rgid`&action=map" a=1}{/capture}
+ {/if}
+ <a href="{$backURL}" title="{ts}Safe Merge Selected Duplicates{/ts}" onclick="return confirm('{ts escape="js"}This will run the batch merge process on the selected duplicates. The operation will run in safe mode - only records with no direct data conflicts will be merged. Click OK to proceed if you are sure you wish to run this operation.{/ts}');" class="button"><span><div class="icon ui-icon-script"></div>{ts}Safe Merge Selected Duplicates{/ts}</span></a>
+ {/if}
+
+ {if $gid}
+ {capture assign=backURL}{crmURL p="civicrm/contact/dedupefind" q="reset=1&action=update&rgid=`$rgid`&gid=`$gid`" a=1}{/capture}
+ {else}
+ {capture assign=backURL}{crmURL p="civicrm/contact/dedupefind" q="reset=1&action=update&rgid=`$rgid`" a=1}{/capture}
+ {/if}
+ <a href="{$backURL}" title="{ts}List All Duplicates{/ts}" class="button"><span><span class="icon ui-icon-refresh"></span> {ts}List All Duplicates{/ts}</span></a>
{else}
{if $gid}
{capture assign=backURL}{crmURL p="civicrm/contact/dedupefind" q="reset=1&rgid=`$rgid`&gid=`$gid`&action=renew" a=1}{/capture}
</a>
{if $gid}
- {capture assign=backURL}{crmURL p="civicrm/contact/dedupefind" q="reset=1&rgid=`$rgid`&gid=`$gid`&action=map" a=1}{/capture}
+ {capture assign=backURL}{crmURL p="civicrm/contact/dedupemerge" q="reset=1&rgid=`$rgid`&gid=`$gid`&action=map" a=1}{/capture}
{else}
- {capture assign=backURL}{crmURL p="civicrm/contact/dedupefind" q="reset=1&rgid=`$rgid`&action=map" a=1}{/capture}
+ {capture assign=backURL}{crmURL p="civicrm/contact/dedupemerge" q="reset=1&rgid=`$rgid`&action=map" a=1}{/capture}
{/if}
- <a href="{$backURL}" title="{ts}Batch Merge Duplicate Contacts{/ts}" onclick="return confirm('{ts escape="js"}This will run the batch merge process on the listed duplicates. The operation will run in safe mode - only records with no direct data conflicts will be merged. Click OK to proceed if you are sure you wish to run this operation.{/ts}');" class="button">
- <span><div class="icon ui-icon-script"></div> {ts}Batch Merge Duplicates{/ts}</span>
- </a>
+ <a href="{$backURL}" title="{ts}Batch Merge Duplicate Contacts{/ts}" onclick="return confirm('{ts escape="js"}This will run the batch merge process on the selected duplicates. The operation will run in safe mode - only records with no direct data conflicts will be merged. Click OK to proceed if you are sure you wish to run this operation.{/ts}');" class="button"><span><div class="icon ui-icon-script"></div>{ts}Batch Merge Selected Duplicates{/ts}</span></a>
+
+ {if $gid}
+ {capture assign=backURL}{crmURL p="civicrm/contact/dedupemerge" q="reset=1&rgid=`$rgid`&gid=`$gid`" a=1}{/capture}
+ {else}
+ {capture assign=backURL}{crmURL p="civicrm/contact/dedupemerge" q="reset=1&rgid=`$rgid`" a=1}{/capture}
+ {/if}
+ <a href="{$backURL}" title="{ts}Batch Merge Duplicate Contacts{/ts}" onclick="return confirm('{ts escape="js"}This will run the batch merge process on the listed duplicates. The operation will run in safe mode - only records with no direct data conflicts will be merged. Click OK to proceed if you are sure you wish to run this operation.{/ts}');" class="button"><span><div class="icon ui-icon-script"></div>{ts}Batch Merge All Duplicates{/ts}</span></a>
+
+ <a href='#' title="{ts}Flip Selected Duplicates{/ts}" class="crm-dedupe-flip-selections button"><span><span class="icon ui-icon-refresh"></span> {ts}Flip Selected Duplicates{/ts}</span></a>
{capture assign=backURL}{crmURL p="civicrm/contact/deduperules" q="reset=1" a=1}{/capture}
<a href="{$backURL}" class="button crm-button-type-cancel">
{include file='CRM/common/dedupe.tpl'}
{literal}
<script type="text/javascript">
-var oTable = null;
+ (function($) {
+ CRM.$('table#dupePairs').data({
+ "ajax": {
+ "url": {/literal}'{$sourceUrl}'{literal}
+ },
+ rowCallback: function (row, data) {
+ // Set the checked state of the checkbox in the table
+ $('input.crm-dedupe-select', row).prop('checked', data.is_selected == 1);
+ if (data.is_selected == 1) {
+ $(row).toggleClass('crm-row-selected');
+ }
+ // for action column at the last, set nowrap
+ $('td:last', row).attr('nowrap','nowrap');
+ // for conflcts column
+ var col = CRM.$('table#dupePairs thead th.crm-contact-conflicts').index();
+ $('td:eq(' + col + ')', row).attr('nowrap','nowrap');
+ }
+ });
+ $(function($) {
+ $('.button').click(function() {
+ // no unsaved changes confirmation dialogs
+ $('[data-warn-changes=true]').attr('data-warn-changes', 'false');
+ });
+
+ var sourceUrl = {/literal}'{$sourceUrl}'{literal};
+ var context = {/literal}'{$context}'{literal};
+
+ // redraw datatable if searching within selected records
+ $('#crm-dedupe-display-selection').on('click', function(){
+ reloadUrl = sourceUrl;
+ if($(this).prop('checked')){
+ reloadUrl = sourceUrl+'&selected=1';
+ }
+ CRM.$('table#dupePairs').DataTable().ajax.url(reloadUrl).draw();
+ });
+
+ $('#dupePairs_length_selection').appendTo('#dupePairs_length');
+
+ // apply selected class on click of a row
+ $('#dupePairs tbody').on('click', 'tr', function(e) {
+ $(this).toggleClass('crm-row-selected');
+ $('input.crm-dedupe-select', this).prop('checked', $(this).hasClass('crm-row-selected'));
+ var ele = $('input.crm-dedupe-select', this);
+ toggleDedupeSelect(ele, 0);
+ });
+
+ // when select-all checkbox is checked
+ $('#dupePairs thead tr .crm-dedupe-selection').on('click', function() {
+ var checked = $('.crm-dedupe-select-all').prop('checked');
+ if (checked) {
+ $("#dupePairs tbody tr input[type='checkbox']").prop('checked', true);
+ $("#dupePairs tbody tr").addClass('crm-row-selected');
+ }
+ else{
+ $("#dupePairs tbody tr input[type='checkbox']").prop('checked', false);
+ $("#dupePairs tbody tr").removeClass('crm-row-selected');
+ }
+ var ele = $('#dupePairs tbody tr');
+ toggleDedupeSelect(ele, 1);
+ });
+
+ // inline search boxes placed in tfoot
+ $('#dupePairsColFilters thead th').each( function () {
+ var title = $('#dupePairs thead th').eq($(this).index()).text();
+ if (title.length > 1) {
+ $(this).html( '<input type="text" placeholder="Search '+title+'" />' );
+ }
+ });
+
+ // get dataTable
+ var table = CRM.$('table#dupePairs').DataTable();
+
+ // apply the search
+ $('#searchOptions input').on( 'keyup change', function () {
+ table
+ .column($(this).attr('search-column'))
+ .search(this.value)
+ .draw();
+ });
+
+ // show / hide columns
+ $('input.toggle-vis').on('click', function (e) {
+ var column = table.column( $(this).attr('data-column-main') );
+ column.visible( ! column.visible() );
+
+ // nowrap to conflicts column is applied only during initial rendering
+ // for show / hide clicks we need to set it explicitly
+ var col = CRM.$('table#dupePairs thead th.crm-contact-conflicts').index() + 1;
+ if (col > 0) {
+ CRM.$('table#dupePairs tbody tr td:nth-child(' + col + ')').attr('nowrap','nowrap');
+ }
+
+ if ($(this).attr('data-column-dupe')) {
+ column = table.column( $(this).attr('data-column-dupe') );
+ column.visible( ! column.visible() );
+ }
+ });
+
+ // keep the conflicts checkbox checked when context is "conflicts"
+ if(context == 'conflicts') {
+ $('#conflicts').attr('checked', true);
+ var column = table.column( $('#conflicts').attr('data-column-main') );
+ column.visible( ! column.visible() );
+ }
+
+ // on click of flip link of a row
+ $('#dupePairs tbody').on('click', 'tr .crm-dedupe-flip', function(e) {
+ e.stopPropagation();
+ var $el = $(this);
+ var $elTr = $(this).closest('tr');
+ var postUrl = {/literal}"{crmURL p='civicrm/ajax/flipDupePairs' h=0 q='snippet=4'}"{literal};
+ var request = $.post(postUrl, {pnid : $el.data('pnid')});
+ request.done(function(dt) {
+ var mapper = {1:3, 2:4, 5:6, 7:8, 9:10}
+ var idx = table.row($elTr).index();
+ $.each(mapper, function(key, val) {
+ var v1 = table.cell(idx, key).data();
+ var v2 = table.cell(idx, val).data();
+ table.cell(idx, key).data(v2);
+ table.cell(idx, val).data(v1);
+ });
+ // keep the checkbox checked if needed
+ $('input.crm-dedupe-select', $elTr).prop('checked', $elTr.hasClass('crm-row-selected'));
+ });
+ });
+
+ $(".crm-dedupe-flip-selections").on('click', function(e) {
+ var ids = [];
+ $('.crm-row-selected').each(function() {
+ var ele = CRM.$('input.crm-dedupe-select', this);
+ ids.push(CRM.$(ele).attr('name').substr(5));
+ });
+ if (ids.length > 0) {
+ var dataUrl = {/literal}"{crmURL p='civicrm/ajax/flipDupePairs' h=0 q='snippet=4'}"{literal};
+ CRM.$.post(dataUrl, {pnid: ids}, function (response) {
+ var mapper = {1:3, 2:4, 5:6, 7:8, 9:10}
+ $('.crm-row-selected').each(function() {
+ var idx = table.row(this).index();
+ $.each(mapper, function(key, val) {
+ var v1 = table.cell(idx, key).data();
+ var v2 = table.cell(idx, val).data();
+ table.cell(idx, key).data(v2);
+ table.cell(idx, val).data(v1);
+ });
+ // keep the checkbox checked if needed
+ $('input.crm-dedupe-select', this).prop('checked', $(this).hasClass('crm-row-selected'));
+ });
+ }, 'json');
+ }
+ });
+ });
+ })(CRM.$);
+
+ function toggleDedupeSelect(element, isMultiple) {
+ if (!isMultiple) {
+ var is_selected = CRM.$(element).prop('checked') ? 1: 0;
+ var id = CRM.$(element).prop('name').substr(5);
+ }
+ else {
+ var id = [];
+ CRM.$(element).each(function() {
+ var sth = CRM.$('input.crm-dedupe-select', this);
+ id.push(CRM.$(sth).prop('name').substr(5));
+ });
+ var is_selected = CRM.$('.crm-dedupe-select-all').prop('checked') ? 1 : 0;
+ }
+
+ var dataUrl = {/literal}"{crmURL p='civicrm/ajax/toggleDedupeSelect' h=0 q='snippet=4'}"{literal};
+ var rgid = {/literal}"{$rgid}"{literal};
+ var gid = {/literal}"{$gid}"{literal};
+
+ rgid = rgid.length > 0 ? rgid : 0;
+ gid = gid.length > 0 ? gid : 0;
+
+ CRM.$.post(dataUrl, {pnid: id, rgid: rgid, gid: gid, is_selected: is_selected}, function (data) {
+ // nothing to do for now
+ }, 'json');
+ }
</script>
{/literal}
--- /dev/null
+{*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.5 |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2014 |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM. |
+ | |
+ | CiviCRM is free software; you can copy, modify, and distribute it |
+ | under the terms of the GNU Affero General Public License |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
+ | |
+ | CiviCRM is distributed in the hope that it will be useful, but |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
+ | See the GNU Affero General Public License for more details. |
+ | |
+ | You should have received a copy of the GNU Affero General Public |
+ | License and the CiviCRM Licensing Exception along |
+ | with this program; if not, contact CiviCRM LLC |
+ | at info[AT]civicrm[DOT]org. If you have questions about the |
+ | GNU Affero General Public License or the licensing of CiviCRM, |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+*}
));
}
+ /**
+ * Test the submit function of the membership form.
+ */
+ public function testSubmitRecurCompleteInstant() {
+ $form = $this->getForm();
+
+ $processor = Civi\Payment\System::singleton()->getById($this->_paymentProcessorID);
+ $processor->setDoDirectPaymentResult(array(
+ 'payment_status_id' => 1,
+ 'trxn_id' => 'kettles boil water',
+ 'fee_amount' => .29,
+ ));
+
+ $this->callAPISuccess('MembershipType', 'create', array(
+ 'id' => $this->membershipTypeAnnualFixedID,
+ 'duration_unit' => 'month',
+ 'duration_interval' => 1,
+ 'auto_renew' => TRUE,
+ ));
+ $this->createLoggedInUser();
+ $form->preProcess();
+
+ $form->_contactID = $this->_individualId;
+ $params = $this->getBaseSubmitParams();
+ $form->_mode = 'test';
+
+ $form->testSubmit($params);
+ $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId));
+ $this->callAPISuccessGetCount('ContributionRecur', array('contact_id' => $this->_individualId), 1);
+
+ $contribution = $this->callAPISuccess('Contribution', 'getsingle', array(
+ 'contact_id' => $this->_individualId,
+ 'is_test' => TRUE,
+ ));
+
+ $this->assertEquals('kettles boil water', $contribution['trxn_id']);
+ $this->assertEquals(.29, $contribution['fee_amount']);
+ $this->assertEquals(78, $contribution['total_amount']);
+ $this->assertEquals(77.71, $contribution['net_amount']);
+
+ $this->callAPISuccessGetCount('LineItem', array(
+ 'entity_id' => $membership['id'],
+ 'entity_table' => 'civicrm_membership',
+ 'contribution_id' => $contribution['id'],
+ ), 1);
+
+ }
/**
* Test the submit function of the membership form.
*/
'record_contribution' => TRUE,
'trxn_id' => 777,
'contribution_status_id' => 1,
+ 'fee_amount' => .5,
);
$form->_contactID = $this->_individualId;
));
$this->assertEquals($contribution['trxn_id'], 777);
+ $this->assertEquals(.5, $contribution['fee_amount']);
$this->callAPISuccessGetCount('LineItem', array(
'entity_id' => $membership['id'],
'entity_table' => 'civicrm_membership',
return $form;
}
+ /**
+ * Get some re-usable parameters for the submit function.
+ *
+ * @return array
+ */
+ protected function getBaseSubmitParams() {
+ $params = array(
+ 'cid' => $this->_individualId,
+ 'price_set_id' => 0,
+ 'join_date' => date('m/d/Y', time()),
+ 'start_date' => '',
+ 'end_date' => '',
+ 'campaign_id' => '',
+ // This format reflects the 23 being the organisation & the 25 being the type.
+ 'membership_type_id' => array(23, $this->membershipTypeAnnualFixedID),
+ 'auto_renew' => '1',
+ 'is_recur' => 1,
+ 'max_related' => 0,
+ 'num_terms' => '1',
+ 'source' => '',
+ 'total_amount' => '78.00',
+ 'financial_type_id' => '2', //Member dues, see data.xml
+ 'soft_credit_type_id' => 11,
+ 'soft_credit_contact_id' => '',
+ 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
+ 'receipt_text' => 'Thank you text',
+ 'payment_processor_id' => $this->_paymentProcessorID,
+ 'credit_card_number' => '4111111111111111',
+ 'cvv2' => '123',
+ 'credit_card_exp_date' => array(
+ 'M' => '9',
+ 'Y' => '2019', // TODO: Future proof
+ ),
+ 'credit_card_type' => 'Visa',
+ 'billing_first_name' => 'Test',
+ 'billing_middlename' => 'Last',
+ 'billing_street_address-5' => '10 Test St',
+ 'billing_city-5' => 'Test',
+ 'billing_state_province_id-5' => '1003',
+ 'billing_postal_code-5' => '90210',
+ 'billing_country_id-5' => '1228',
+ );
+ return $params;
+ }
+
}
'billing_postal_code-5' => '90210',
'billing_country_id-5' => '1228',
);
- $form->submit($params);
+ $form->_contactID = $this->_individualId;
+ $form->testSubmit($params);
$membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId));
$this->callAPISuccessGetCount('ContributionRecur', array('contact_id' => $this->_individualId), 0);
$contribution = $this->callAPISuccess('Contribution', 'get', array(
$this->createLoggedInUser();
$params = $this->getBaseSubmitParams();
$form->_mode = 'test';
-
- $form->submit($params);
+ $form->_contactID = $this->_individualId;
+ $form->testSubmit($params);
$membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId));
$this->callAPISuccessGetCount('ContributionRecur', array('contact_id' => $this->_individualId), 1);
), 1);
}
+ /**
+ * Test the submit function of the membership form.
+ */
+ public function testSubmitPayLaterWithBilling() {
+ $form = $this->getForm(NULL);
+ $this->createLoggedInUser();
+ $params = array(
+ 'cid' => $this->_individualId,
+ 'join_date' => date('m/d/Y', time()),
+ 'start_date' => '',
+ 'end_date' => '',
+ // This format reflects the 23 being the organisation & the 25 being the type.
+ 'membership_type_id' => array(23, $this->membershipTypeAnnualFixedID),
+ 'auto_renew' => '0',
+ 'max_related' => '',
+ 'num_terms' => '2',
+ 'source' => '',
+ 'total_amount' => '50.00',
+ //Member dues, see data.xml
+ 'financial_type_id' => '2',
+ 'soft_credit_type_id' => '',
+ 'soft_credit_contact_id' => '',
+ 'payment_instrument_id' => 4,
+ 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
+ 'receipt_text_signup' => 'Thank you text',
+ 'payment_processor_id' => $this->_paymentProcessorID,
+ 'record_contribution' => TRUE,
+ 'trxn_id' => 777,
+ 'contribution_status_id' => 2,
+ 'billing_first_name' => 'Test',
+ 'billing_middlename' => 'Last',
+ 'billing_street_address-5' => '10 Test St',
+ 'billing_city-5' => 'Test',
+ 'billing_state_province_id-5' => '1003',
+ 'billing_postal_code-5' => '90210',
+ 'billing_country_id-5' => '1228',
+ );
+ $form->_contactID = $this->_individualId;
+
+ $form->testSubmit($params);
+ $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId));
+ $contribution = $this->callAPISuccessGetSingle('Contribution', array(
+ 'contact_id' => $this->_individualId,
+ 'contribution_status_id' => 2,
+ ));
+ $this->assertEquals($contribution['trxn_id'], 777);
+
+ $this->callAPISuccessGetCount('LineItem', array(
+ 'entity_id' => $membership['id'],
+ 'entity_table' => 'civicrm_membership',
+ 'contribution_id' => $contribution['id'],
+ ), 1);
+ $this->callAPISuccessGetSingle('address', array(
+ 'contact_id' => $this->_individualId,
+ 'street_address' => '10 Test St',
+ 'postal_code' => 90210,
+ ));
+ }
+
/**
* Test the submit function of the membership form.
*/
$form = $this->getForm();
$processor = Civi\Payment\System::singleton()->getById($this->_paymentProcessorID);
- $processor->setDoDirectPaymentResult(array('payment_status_id' => 1, 'trxn_id' => 'kettles boil water'));
+ $processor->setDoDirectPaymentResult(array(
+ 'payment_status_id' => 1,
+ 'trxn_id' => 'kettles boil water',
+ 'fee_amount' => .14,
+ ));
$this->callAPISuccess('MembershipType', 'create', array(
'id' => $this->membershipTypeAnnualFixedID,
'duration_unit' => 'month',
$this->createLoggedInUser();
$params = $this->getBaseSubmitParams();
$form->_mode = 'test';
-
- $form->submit($params);
+ $form->_contactID = $this->_individualId;
+ $form->testSubmit($params);
$membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId));
$this->callAPISuccessGetCount('ContributionRecur', array('contact_id' => $this->_individualId), 1);
- $contribution = $this->callAPISuccess('Contribution', 'get', array(
+ $contribution = $this->callAPISuccess('Contribution', 'getsingle', array(
'contact_id' => $this->_individualId,
'is_test' => TRUE,
));
+ $this->assertEquals(.14, $contribution['fee_amount']);
+ $this->assertEquals('kettles boil water', $contribution['trxn_id']);
+
$this->callAPISuccessGetCount('LineItem', array(
'entity_id' => $membership['id'],
'entity_table' => 'civicrm_membership',
public function setUp() {
parent::setUp();
-
- $this->_populateOptionAndCustomGroup();
}
- public function _populateOptionAndCustomGroup() {
+ public function _populateOptionAndCustomGroup($type = NULL) {
$dataValues = array(
'integer' => array(1, 2, 3),
'number' => array(10.11, 20.22, 30.33),
'string' => array(substr(sha1(rand()), 0, 4), substr(sha1(rand()), 0, 3), substr(sha1(rand()), 0, 2)),
- 'country' => array_rand(CRM_Core_PseudoConstant::country(FALSE, FALSE), 3),
+ //'country' => array_rand(CRM_Core_PseudoConstant::country(FALSE, FALSE), 3),
'state_province' => array_rand(CRM_Core_PseudoConstant::stateProvince(FALSE, FALSE), 3),
'date' => NULL,
'contact' => NULL,
);
+ $dataValues = !empty($type) ? array($type => $dataValues[$type]) : $dataValues;
+
foreach ($dataValues as $dataType => $values) {
$this->optionGroup[$dataType] = array('values' => $values);
if (!empty($values)) {
// true tells quickCleanup to drop any tables that might have been created in the test
$this->quickCleanup($tablesToTruncate, TRUE);
+
+ // cleanup created option group for each custom-set before running next test
+ if (!empty($this->optionGroup)) {
+ foreach ($this->optionGroup as $type => $value) {
+ if (!empty($value['id'])) {
+ $this->callAPISuccess('OptionGroup', 'delete', array('id' => $value['id']));
+ }
+ }
+ }
}
public function testCreateCustomValue() {
+ $this->_populateOptionAndCustomGroup();
+
$customFieldDataType = CRM_Core_BAO_CustomField::dataType();
$dataToHtmlTypes = CRM_Core_BAO_CustomField::dataToHtml();
$count = 0;
$type = 'string';
}
else {
- if ($dataType == 'Country') {
- $type == 'country';
- }
- elseif ($dataType == 'StateProvince') {
+ if ($dataType == 'StateProvince') {
$type = 'state_province';
}
elseif ($dataType == 'ContactReference') {
* @throws \CiviCRM_API3_Exception
*/
public function testAlterOptionValue() {
+ $this->_populateOptionAndCustomGroup('string');
+
$selectField = $this->customFieldCreate(array(
- 'custom_group_id' => $this->ids['single']['custom_group_id'],
+ 'custom_group_id' => $this->ids['string']['custom_group_id'],
'label' => 'Custom Select',
'html_type' => 'Select',
- 'option_values' => array(
- 'one' => 'Option1',
- 'two' => 'Option2',
- 'notone' => 'OptionNotOne',
- ),
+ 'option_group_id' => $this->optionGroup['string']['id'],
));
$selectField = civicrm_api3('customField', 'getsingle', array('id' => $selectField['id']));
$radioField = $this->customFieldCreate(array(
- 'custom_group_id' => $this->ids['single']['custom_group_id'],
+ 'custom_group_id' => $this->ids['string']['custom_group_id'],
'label' => 'Custom Radio',
'html_type' => 'Radio',
'option_group_id' => $selectField['option_group_id'],
));
$multiSelectField = $this->customFieldCreate(array(
- 'custom_group_id' => $this->ids['single']['custom_group_id'],
+ 'custom_group_id' => $this->ids['string']['custom_group_id'],
'label' => 'Custom Multi-Select',
'html_type' => 'Multi-Select',
'option_group_id' => $selectField['option_group_id'],
$selectName = 'custom_' . $selectField['id'];
$radioName = 'custom_' . $radioField['id'];
$multiSelectName = 'custom_' . $multiSelectField['id'];
- $controlFieldName = 'custom_' . $this->ids['single']['custom_field_id'];
+ $controlFieldName = 'custom_' . $this->ids['string']['custom_field_id'];
$params = array(
'first_name' => 'abc4',
'last_name' => 'xyz4',
'contact_type' => 'Individual',
'email' => 'man4@yahoo.com',
- $selectName => 'one',
- $multiSelectName => array('one', 'two', 'notone'),
- $radioName => 'notone',
+ $selectName => $this->optionGroup['string']['values'][0],
+ $multiSelectName => $this->optionGroup['string']['values'],
+ $radioName => $this->optionGroup['string']['values'][1],
// The control group in a science experiment should be unaffected
- $controlFieldName => 'one',
+ $controlFieldName => $this->optionGroup['string']['values'][2],
);
$contact = $this->callAPISuccess('Contact', 'create', $params);
'id' => $contact['id'],
'return' => array($selectName, $multiSelectName),
));
- $this->assertEquals('one', $result[$selectName]);
- $this->assertEquals(array('one', 'two', 'notone'), $result[$multiSelectName]);
+ $this->assertEquals($params[$selectName], $result[$selectName]);
+ $this->assertEquals($params[$multiSelectName], $result[$multiSelectName]);
$this->callAPISuccess('OptionValue', 'create', array(
'value' => 'one-modified',
'option_group_id' => $selectField['option_group_id'],
- 'name' => 'Option1',
+ 'name' => 'string 1',
'options' => array(
'match-mandatory' => array('option_group_id', 'name'),
),
));
// Ensure the relevant fields have been updated
$this->assertEquals('one-modified', $result[$selectName]);
- $this->assertEquals(array('one-modified', 'two', 'notone'), $result[$multiSelectName]);
+ $this->assertEquals(array('one-modified', $params[$radioName], $params[$controlFieldName]), $result[$multiSelectName]);
// This field should not have changed because we didn't alter this option
- $this->assertEquals('notone', $result[$radioName]);
+ $this->assertEquals($params[$radioName], $result[$radioName]);
// This should not have changed because this field doesn't use the affected option group
- $this->assertEquals('one', $result[$controlFieldName]);
+ $this->assertEquals($params[$controlFieldName], $result[$controlFieldName]);
}
}