CRM-16632 - Fix calculation of contribution fees
[civicrm-core.git] / CRM / Profile / Form.php
index c0dee2b655c79c8c05d7d89e94dbaf0f35a40b95..cf276a1c374b9e15d1361a6f229ec24dc3954d5f 100644 (file)
@@ -3,7 +3,7 @@
  +--------------------------------------------------------------------+
  | CiviCRM version 4.6                                                |
  +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2014                                |
+ | Copyright CiviCRM LLC (c) 2004-2015                                |
  +--------------------------------------------------------------------+
  | This file is a part of CiviCRM.                                    |
  |                                                                    |
  | 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
+ * @copyright CiviCRM LLC (c) 2004-2015
  * $Id$
  *
  */
 class CRM_Profile_Form extends CRM_Core_Form {
   const
     MODE_REGISTER = 1,
-    MODE_SEARCH   = 2,
-    MODE_CREATE   = 4,
-    MODE_EDIT     = 8;
+    MODE_SEARCH = 2,
+    MODE_CREATE = 4,
+    MODE_EDIT = 8;
 
   protected $_mode;
 
   protected $_skipPermission = FALSE;
 
   /**
-   * The contact id that we are editing
+   * The contact id that we are editing.
    *
    * @var int
    */
   protected $_id;
 
   /**
-   * The group id that we are editing
+   * The group id that we are editing.
    *
    * @var int
    */
@@ -72,45 +72,51 @@ class CRM_Profile_Form extends CRM_Core_Form {
   protected $_ufGroup = array('name' => 'unknown');
 
   /**
-   * The group id that we are passing in url
+   * The group id that we are passing in url.
    *
    * @var int
    */
   public $_grid;
 
   /**
-   * Name of button for saving matching contacts
+   * Name of button for saving matching contacts.
    * @var
    */
   protected $_duplicateButtonName;
   /**
-   * The title of the category we are editing
+   * The title of the category we are editing.
    *
    * @var string
    */
   protected $_title;
 
   /**
-   * The fields needed to build this form
+   * The fields needed to build this form.
    *
    * @var array
    */
   public $_fields;
 
   /**
-   * To store contact details
+   * store contact details.
    *
    * @var array
    */
   protected $_contact;
 
   /**
-   * Do we allow updates of the contact
+   * Do we allow updates of the contact.
    *
    * @var int
    */
   public $_isUpdateDupe = 0;
 
+  /**
+   * Dedupe using a specific rule (CRM-6131).
+   * Not currently exposed in profile settings, but can be set in a buildForm hook.
+   */
+  public $_ruleGroupID = NULL;
+
   public $_isAddCaptcha = FALSE;
 
   protected $_isPermissionedChecksum = FALSE;
@@ -123,7 +129,7 @@ class CRM_Profile_Form extends CRM_Core_Form {
   protected $_context;
 
   /**
-   * THe contact type for registration case
+   * THe contact type for registration case.
    *
    * @var string
    */
@@ -145,7 +151,7 @@ class CRM_Profile_Form extends CRM_Core_Form {
   protected $_isContactActivityProfile = FALSE;
 
   /**
-   * Activity Id connected to the profile
+   * Activity Id connected to the profile.
    *
    * @var string
    */
@@ -174,7 +180,7 @@ class CRM_Profile_Form extends CRM_Core_Form {
   protected $_customGroupId = NULL;
 
   protected $_currentUserID = NULL;
-  protected $_session       = NULL;
+  protected $_session = NULL;
 
   /**
    * Pre processing work done here.
@@ -184,13 +190,12 @@ class CRM_Profile_Form extends CRM_Core_Form {
    * @param
    *
    * @return void
-   *
    */
   public function preProcess() {
-    $this->_id         = $this->get('id');
+    $this->_id = $this->get('id');
     $this->_profileIds = $this->get('profileIds');
-    $this->_grid       = CRM_Utils_Request::retrieve('grid', 'Integer', $this);
-    $this->_context    = CRM_Utils_Request::retrieve('context', 'String', $this);
+    $this->_grid = CRM_Utils_Request::retrieve('grid', 'Integer', $this);
+    $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this);
 
     //unset from session when $_GET doesn't have it
     //except when the form is submitted
@@ -209,14 +214,14 @@ class CRM_Profile_Form extends CRM_Core_Form {
     if ($this->_mode == self::MODE_EDIT) {
       //specifies the action being done on a multi record field
       $multiRecordAction = CRM_Utils_Request::retrieve('multiRecord', 'String', $this);
-      $this->_multiRecord = (!is_numeric($multiRecordAction)) ?
-        CRM_Core_Action::resolve($multiRecordAction) : $multiRecordAction;
+      $this->_multiRecord = (!is_numeric($multiRecordAction)) ? CRM_Core_Action::resolve($multiRecordAction) : $multiRecordAction;
       if ($this->_multiRecord) {
         $this->set('multiRecord', $this->_multiRecord);
       }
 
       if ($this->_multiRecord &&
-          !in_array($this->_multiRecord, array(CRM_Core_Action::UPDATE, CRM_Core_Action::ADD, CRM_Core_Action::DELETE))) {
+        !in_array($this->_multiRecord, array(CRM_Core_Action::UPDATE, CRM_Core_Action::ADD, CRM_Core_Action::DELETE))
+      ) {
         CRM_Core_Error::fatal(ts('Proper action not specified for this custom value record profile'));
       }
     }
@@ -310,18 +315,21 @@ class CRM_Profile_Form extends CRM_Core_Form {
         if ($this->_multiRecord) {
           if ($this->_multiRecord != CRM_Core_Action::ADD) {
             $this->_recordId = CRM_Utils_Request::retrieve('recordId', 'Positive', $this);
-          } else {
+          }
+          else {
             $this->_recordId = NULL;
             $this->set('recordId', NULL);
           }
           //record id is neccessary for _multiRecord view and update/edit action
           if (!$this->_recordId
-              && ($this->_multiRecord == CRM_Core_Action::UPDATE || $this->_multiRecord == CRM_Core_Action::DELETE)) {
+            && ($this->_multiRecord == CRM_Core_Action::UPDATE || $this->_multiRecord == CRM_Core_Action::DELETE)
+          ) {
             CRM_Core_Error::fatal(ts('The requested Profile (gid=%1) requires record id while performing this action',
               array(1 => $this->_gid)
             ));
-          } elseif (empty($this->_multiRecordFields)) {
-              CRM_Core_Error::fatal(ts('No Multi-Record Fields configured for this profile (gid=%1)',
+          }
+          elseif (empty($this->_multiRecordFields)) {
+            CRM_Core_Error::fatal(ts('No Multi-Record Fields configured for this profile (gid=%1)',
               array(1 => $this->_gid)
             ));
           }
@@ -340,7 +348,8 @@ class CRM_Profile_Form extends CRM_Core_Form {
 
             if (array_key_exists($this->_recordId, $getValues)) {
               $this->_recordExists = TRUE;
-            } else {
+            }
+            else {
               $this->_recordExists = FALSE;
               if ($this->_multiRecord & CRM_Core_Action::UPDATE) {
                 CRM_Core_Session::setStatus(ts('Note: The record %1 doesnot exists. Upon save a new record will be create', array(1 => $this->_recordId)), ts('Record doesnot exist'), 'alert');
@@ -354,8 +363,13 @@ class CRM_Profile_Form extends CRM_Core_Form {
             }
           }
 
-        } elseif (!empty($this->_multiRecordFields)
-           && (!$this->_multiRecord || !in_array($this->_multiRecord, array(CRM_Core_Action::DELETE, CRM_Core_Action::UPDATE)) )) {
+        }
+        elseif (!empty($this->_multiRecordFields)
+          && (!$this->_multiRecord || !in_array($this->_multiRecord, array(
+                CRM_Core_Action::DELETE,
+                CRM_Core_Action::UPDATE,
+              )))
+        ) {
           CRM_Core_Resources::singleton()->addScriptFile('civicrm', 'js/crm.livePage.js', 1, 'html-header');
           //multirecord listing page
           $multiRecordFieldListing = TRUE;
@@ -392,7 +406,8 @@ class CRM_Profile_Form extends CRM_Core_Form {
       if ($this->_multiRecord && !empty($this->_multiRecordFields)) {
         $this->_fields = $this->_multiRecordFields;
         $this->_multiRecordProfile = TRUE;
-      } elseif ($this->_multiRecord && empty($this->_multiRecordFields)) {
+      }
+      elseif ($this->_multiRecord && empty($this->_multiRecordFields)) {
         CRM_Core_Session::setStatus(ts('This feature is not currently available.'), ts('Sorry'), 'error');
         CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm', 'reset=1'));
       }
@@ -450,12 +465,13 @@ class CRM_Profile_Form extends CRM_Core_Form {
         $fieldIds[] = CRM_Core_BAO_CustomField::getKeyID($key);
       }
 
-      $defaultValues = array( );
+      $defaultValues = array();
       if ($this->_multiRecord && $this->_multiRecord == CRM_Core_Action::UPDATE) {
         $defaultValues = CRM_Core_BAO_CustomValueTable::getEntityValues($this->_id, NULL, $fieldIds, TRUE);
         if ($this->_recordExists == TRUE) {
           $defaultValues = $defaultValues[$this->_recordId];
-        } else {
+        }
+        else {
           $defaultValues = NULL;
         }
       }
@@ -473,7 +489,8 @@ class CRM_Profile_Form extends CRM_Core_Form {
                 $this->_mode,
                 $value
               );
-            } else {
+            }
+            else {
               $this->_defaults[$name] = "";
             }
           }
@@ -481,8 +498,8 @@ class CRM_Profile_Form extends CRM_Core_Form {
           if ($htmlType == 'File') {
             $entityId = $this->_id;
             if (CRM_Utils_Array::value('field_type', $field) == 'Activity' &&
-                $this->_activityId
-                ) {
+              $this->_activityId
+            ) {
               $entityId = $this->_activityId;
             }
             $url = CRM_Core_BAO_CustomField::getFileURL($entityId, $key);
@@ -491,10 +508,10 @@ class CRM_Profile_Form extends CRM_Core_Form {
               $customFiles[$name]['displayURL'] = ts("Attached File") . ": {$url['file_url']}";
 
               $deleteExtra = ts("Are you sure you want to delete attached file?");
-              $fileId      = $url['file_id'];
-              $deleteURL   = CRM_Utils_System::url('civicrm/file',
-                             "reset=1&id={$fileId}&eid=$entityId&fid={$key}&action=delete"
-                           );
+              $fileId = $url['file_id'];
+              $deleteURL = CRM_Utils_System::url('civicrm/file',
+                "reset=1&id={$fileId}&eid=$entityId&fid={$key}&action=delete"
+              );
               $text = ts("Delete Attached File");
               $customFiles[$field['name']]['deleteURL'] = "<a href=\"{$deleteURL}\" onclick = \"if (confirm( ' $deleteExtra ' )) this.href+='&amp;confirmed=1'; else return false;\">$text</a>";
 
@@ -510,8 +527,8 @@ class CRM_Profile_Form extends CRM_Core_Form {
         if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($name)) {
           $htmlType = $field['html_type'];
           if ((!isset($this->_defaults[$name]) || $htmlType == 'File') &&
-              (CRM_Utils_Array::value('field_type', $field) != 'Activity')
-              ) {
+            (CRM_Utils_Array::value('field_type', $field) != 'Activity')
+          ) {
             CRM_Core_BAO_CustomField::setProfileDefaults($customFieldID,
               $name,
               $this->_defaults,
@@ -531,9 +548,9 @@ class CRM_Profile_Form extends CRM_Core_Form {
               $customFiles[$field['name']]['displayURL'] = ts("Attached File") . ": {$url['file_url']}";
 
               $deleteExtra = ts("Are you sure you want to delete attached file?");
-              $fileId      = $url['file_id'];
-              $deleteURL   = CRM_Utils_System::url('civicrm/file',
-                 "reset=1&id={$fileId}&eid=$entityId&fid={$customFieldID}&action=delete"
+              $fileId = $url['file_id'];
+              $deleteURL = CRM_Utils_System::url('civicrm/file',
+                "reset=1&id={$fileId}&eid=$entityId&fid={$customFieldID}&action=delete"
               );
               $text = ts("Delete Attached File");
               $customFiles[$field['name']]['deleteURL'] = "<a href=\"{$deleteURL}\" onclick = \"if (confirm( ' $deleteExtra ' )) this.href+='&amp;confirmed=1'; else return false;\">$text</a>";
@@ -577,7 +594,7 @@ class CRM_Profile_Form extends CRM_Core_Form {
   }
 
   /**
-   * Build the form object
+   * Build the form object.
    *
    * @return void
    */
@@ -590,9 +607,11 @@ class CRM_Profile_Form extends CRM_Core_Form {
       case self::MODE_REGISTER:
         CRM_Utils_Hook::buildProfile($this->_ufGroup['name']);
         break;
+
       case self::MODE_SEARCH:
         CRM_Utils_Hook::searchProfile($this->_ufGroup['name']);
         break;
+
       default:
     }
 
@@ -636,7 +655,7 @@ class CRM_Profile_Form extends CRM_Core_Form {
 
       if ($this->_id) {
         $contactTypes = CRM_Contact_BAO_Contact::getContactTypes($this->_id);
-        $contactType  = $contactTypes[0];
+        $contactType = $contactTypes[0];
 
         array_shift($contactTypes);
         $contactSubtypes = $contactTypes;
@@ -649,23 +668,22 @@ class CRM_Profile_Form extends CRM_Core_Form {
 
         if (
           ($profileType != 'Contact' && !$this->_isContactActivityProfile) &&
-          (($profileSubType && !empty($contactSubtypes) && (!in_array($profileSubType,$contactSubtypes))) ||
+          (($profileSubType && !empty($contactSubtypes) && (!in_array($profileSubType, $contactSubtypes))) ||
             ($profileType != $contactType))
         ) {
           $return = TRUE;
           if (!$statusMessage) {
-            $statusMessage =
-              ts("This profile is configured for contact type '%1'. It cannot be used to edit contacts of other types.",
+            $statusMessage = ts("This profile is configured for contact type '%1'. It cannot be used to edit contacts of other types.",
                 array(1 => $profileSubType ? $profileSubType : $profileType));
           }
         }
       }
 
       if (
-        in_array(
-          $profileType,
-          array("Membership", "Participant", "Contribution")
-        )
+      in_array(
+        $profileType,
+        array("Membership", "Participant", "Contribution")
+      )
       ) {
         $return = TRUE;
         if (!$statusMessage) {
@@ -716,7 +734,7 @@ class CRM_Profile_Form extends CRM_Core_Form {
     if (!$this->_currentUserID) {
       $defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
       $primaryLocationType = $defaultLocationType->id;
-      $anonUser            = TRUE;
+      $anonUser = TRUE;
     }
     $this->assign('anonUser', $anonUser);
 
@@ -763,7 +781,7 @@ class CRM_Profile_Form extends CRM_Core_Form {
       if ($this->_currentUserID) {
         $this->_isAddCaptcha = FALSE;
       }
-      else if (!$this->_isAddCaptcha && !empty($addCaptcha)) {
+      elseif (!$this->_isAddCaptcha && !empty($addCaptcha)) {
         $this->_isAddCaptcha = TRUE;
       }
 
@@ -824,7 +842,7 @@ class CRM_Profile_Form extends CRM_Core_Form {
   }
 
   /**
-   * Validate profile and provided activity Id
+   * Validate profile and provided activity Id.
    *
    * @param int $activityId
    * @param int $contactId
@@ -864,14 +882,17 @@ class CRM_Profile_Form extends CRM_Core_Form {
   }
 
   /**
-   * Global form rule
+   * Global form rule.
    *
-   * @param array  $fields the input form values
-   * @param array  $files  the uploaded files if any
-   * @param CRM_Core_Form $form   the form object
+   * @param array $fields
+   *   The input form values.
+   * @param array $files
+   *   The uploaded files if any.
+   * @param CRM_Core_Form $form
+   *   The form object.
    *
-   * @return true if no errors, else array of errors
-   * @static
+   * @return bool|array
+   *   true if no errors, else array of errors
    */
   public static function formRule($fields, $files, $form) {
     CRM_Utils_Hook::validateProfile($form->_ufGroup['name']);
@@ -931,7 +952,8 @@ class CRM_Profile_Form extends CRM_Core_Form {
       $ids = CRM_Dedupe_Finder::dupesByParams($dedupeParams,
         $ctype,
         $ruleType,
-        $exceptions
+        $exceptions,
+        $form->_ruleGroupID
       );
       if ($ids) {
         if ($form->_isUpdateDupe == 2) {
@@ -947,17 +969,26 @@ class CRM_Profile_Form extends CRM_Core_Form {
             $contactLinks = CRM_Contact_BAO_Contact_Utils::formatContactIDSToLinks($ids, TRUE, TRUE);
 
             $duplicateContactsLinks = '<div class="matching-contacts-found">';
-            $duplicateContactsLinks .= ts('One matching contact was found. ', array('count' => count($contactLinks['rows']), 'plural' => '%count matching contacts were found.<br />'));
+            $duplicateContactsLinks .= ts('One matching contact was found. ', array(
+                'count' => count($contactLinks['rows']),
+                'plural' => '%count matching contacts were found.<br />',
+              ));
             if ($contactLinks['msg'] == 'view') {
-              $duplicateContactsLinks .= ts('You can View the existing contact.', array('count' => count($contactLinks['rows']), 'plural' => 'You can View the existing contacts.'));
+              $duplicateContactsLinks .= ts('You can View the existing contact.', array(
+                  'count' => count($contactLinks['rows']),
+                  'plural' => 'You can View the existing contacts.',
+                ));
             }
             else {
-              $duplicateContactsLinks .= ts('You can View or Edit the existing contact.', array('count' => count($contactLinks['rows']), 'plural' => 'You can View or Edit the existing contacts.'));
+              $duplicateContactsLinks .= ts('You can View or Edit the existing contact.', array(
+                  'count' => count($contactLinks['rows']),
+                  'plural' => 'You can View or Edit the existing contacts.',
+                ));
             }
             $duplicateContactsLinks .= '</div>';
             $duplicateContactsLinks .= '<table class="matching-contacts-actions">';
             $row = '';
-            for ($i = 0; $i < sizeof($contactLinks['rows']); $i++) {
+            for ($i = 0; $i < count($contactLinks['rows']); $i++) {
               $row .= '  <tr>   ';
               $row .= '    <td class="matching-contacts-name"> ';
               $row .= $contactLinks['rows'][$i]['display_name'];
@@ -1003,8 +1034,8 @@ class CRM_Profile_Form extends CRM_Core_Form {
           if ($stateProvinceDAO->country_id != $countryId) {
             // country mismatch hence display error
             $stateProvinces = CRM_Core_PseudoConstant::stateProvince();
-            $countries      = CRM_Core_PseudoConstant::country();
-            $errors[$key]   = "State/Province " . $stateProvinces[$stateProvinceId] . " is not part of " . $countries[$countryId] . ". It belongs to " . $countries[$stateProvinceDAO->country_id] . ".";
+            $countries = CRM_Core_PseudoConstant::country();
+            $errors[$key] = "State/Province " . $stateProvinces[$stateProvinceId] . " is not part of " . $countries[$countryId] . ". It belongs to " . $countries[$stateProvinceDAO->country_id] . ".";
           }
         }
       }
@@ -1022,8 +1053,8 @@ class CRM_Profile_Form extends CRM_Core_Form {
           if ($countyDAO->state_province_id != $stateProvinceId) {
             // state province mismatch hence display error
             $stateProvinces = CRM_Core_PseudoConstant::stateProvince();
-            $counties       = CRM_Core_PseudoConstant::county();
-            $errors[$key]   = "County " . $counties[$countyId] . " is not part of " . $stateProvinces[$stateProvinceId] . ". It belongs to " . $stateProvinces[$countyDAO->state_province_id] . ".";
+            $counties = CRM_Core_PseudoConstant::county();
+            $errors[$key] = "County " . $counties[$countyId] . " is not part of " . $stateProvinces[$stateProvinceId] . ". It belongs to " . $stateProvinces[$countyDAO->state_province_id] . ".";
           }
         }
       }
@@ -1061,11 +1092,11 @@ class CRM_Profile_Form extends CRM_Core_Form {
           if ($tableName = CRM_Utils_Array::value('table_name', $returnValues)) {
             $sql = "DELETE FROM {$tableName} WHERE id = %1 AND entity_id = %2";
             $sqlParams = array(
-                          1 => array($this->_recordId, 'Integer'),
-                          2 => array($this->_id, 'Integer')
-                         );
-           CRM_Core_DAO::executeQuery($sql, $sqlParams);
-           CRM_Core_Session::setStatus(ts('Your record has been deleted.'), ts('Deleted'), 'success');
+              1 => array($this->_recordId, 'Integer'),
+              2 => array($this->_id, 'Integer'),
+            );
+            CRM_Core_DAO::executeQuery($sql, $sqlParams);
+            CRM_Core_Session::setStatus(ts('Your record has been deleted.'), ts('Deleted'), 'success');
           }
         }
         return;
@@ -1090,8 +1121,9 @@ class CRM_Profile_Form extends CRM_Core_Form {
       $details = $contactDetails[0][$this->_id];
     }
     if (!(!empty($details['addressee_id']) || !empty($details['email_greeting_id']) ||
-        CRM_Utils_Array::value('postal_greeting_id', $details)
-      )) {
+      CRM_Utils_Array::value('postal_greeting_id', $details)
+    )
+    ) {
 
       $profileType = CRM_Core_BAO_UFField::getProfileType($this->_gid);
       //Though Profile type is contact we need
@@ -1295,8 +1327,8 @@ class CRM_Profile_Form extends CRM_Core_Form {
         CRM_Core_Error::debug_log_message("Rolling back transaction as CMSUser Create failed in Profile_Form for contact " . $params['contactID']);
         $transaction->rollback();
         return CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/profile/create',
-            'reset=1&gid=' . $this->_gid
-          ));
+          'reset=1&gid=' . $this->_gid
+        ));
       }
     }
 
@@ -1329,7 +1361,7 @@ class CRM_Profile_Form extends CRM_Core_Form {
   }
 
   /**
-   * Use the form name to create the tpl file name
+   * Use the form name to create the tpl file name.
    *
    * @return string
    */
@@ -1354,4 +1386,5 @@ class CRM_Profile_Form extends CRM_Core_Form {
     $fileName = $this->checkTemplateFileExists('extra.');
     return $fileName ? $fileName : parent::overrideExtraTemplateFileName();
   }
+
 }