CRM-13179 make autoselect available for logged in users
authoreileen <eileen@fuzion.co.nz>
Wed, 14 Aug 2013 06:14:14 +0000 (18:14 +1200)
committereileen <eileen@fuzion.co.nz>
Sun, 18 Aug 2013 04:49:44 +0000 (16:49 +1200)
CRM/Contribute/Form/Contribution/Confirm.php
CRM/Contribute/Form/Contribution/Main.php
CRM/Core/Form.php
CRM/Event/Form/Registration/Register.php
templates/CRM/Contribute/Form/Contribution/Main.tpl
templates/CRM/Event/Form/Registration/Register.tpl
templates/CRM/common/AutoComplete.js [new file with mode: 0644]
templates/CRM/common/cidzero.tpl [new file with mode: 0644]

index 2bf4640ffbd3807b24b4c2ab55721b1d80c673d7..dfd6771ffd9cf372a96e7fbd336bf28726cca2cf 100644 (file)
@@ -798,6 +798,7 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
 
     // Make the contact ID associated with the contribution available at the Class level.
     // Also make available to the session.
+    //@todo consider handling this in $this->getContactID();
     $this->set('contactID', $contactID);
     $this->_contactID = $contactID;
 
index c5a00586041d96c357207378eefc377f51403c2a..f28cccee90e60c8ebfff64f9782f7750e5e55576 100644 (file)
@@ -393,9 +393,12 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu
     );
     $this->addRule("email-{$this->_bltID}", ts('Email is not valid.'), 'email');
     $pps = array();
+    $onlinePaymentProcessorEnabled = FALSE;
     if (!empty($this->_paymentProcessors)) {
-      $pps = $this->_paymentProcessors;
-      foreach ($pps as $key => & $name) {
+      foreach ($this->_paymentProcessors as $key => $name) {
+        if($name['billing_mode'] == 1) {
+          $onlinePaymentProcessorEnabled = TRUE;
+        }
         $pps[$key] = $name['name'];
       }
     }
@@ -417,6 +420,11 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu
         $this->assign('pay_later_text', $this->_values['pay_later_text']);
       }
     }
+
+    $contactID = $this->getContactID();
+    if($this->getContactID() === '0') {
+      $this->addCidZeroOptions($onlinePaymentProcessorEnabled);
+    }
     //build pledge block.
     $this->_useForMember = 0;
     //don't build membership block when pledge_id is passed
index 074889a958fb26f90e0c80acdc795785b1aaa9ca..ad6b4730e940b390943bbf66138bc0b48da7827e 100644 (file)
@@ -1318,15 +1318,16 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
  */
   function getContactID() {
     $tempID = CRM_Utils_Request::retrieve('cid', 'Positive', $this);
+    if(isset($this->_params) && isset($this->_params['select_contact_id '])) {
+      $tempID = $this->_params['select_contact_id'];
+    }
 
     // force to ignore the authenticated user
     if ($tempID === '0') {
       return $tempID;
     }
 
-    // check if the user is logged in and has a contact ID
-    $session = CRM_Core_Session::singleton();
-    $userID = $session->get('userID');
+    $userID = $this->getLoggedInUserContactID();
 
     if ($tempID == $userID) {
       return $userID;
@@ -1348,5 +1349,86 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
 
     return $userID;
   }
+
+ /**
+  * Get the contact id of the logged in user
+  */
+  function getLoggedInUserContactID() {
+    // check if the user is logged in and has a contact ID
+    $session = CRM_Core_Session::singleton();
+    return $session->get('userID');
+  }
+
+  /**
+   * add autoselector field -if user has permission to view contacts
+   * If adding this to a form you also need to add to the tpl e.g
+   *
+   * {if !empty($selectable)}
+   * <div class="crm-summary-row">
+   *   <div class="crm-label">{$form.select_contact.label}</div>
+   *   <div class="crm-content">
+   *     {$form.select_contact.html}
+   *   </div>
+   * </div>
+   * {/if}
+   * @param array $profiles ids of profiles that are on the form (to be autofilled)
+   * @param array $field metadata of field to use as selector including
+   *  - name_field
+   *  - id_field
+   *  - url (for ajax lookup)
+   *
+   *  @todo add data attributes so we can deal with multiple instances on a form
+   */
+  function addAutoSelector($profiles = array(), $autoCompleteField = array()) {
+    $autoCompleteField = array_merge(array(
+        'name_field' => 'select_contact',
+        'id_field' => 'select_contact_id',
+        'field_text' => ts('Select Contact'),
+        'show_hide' => TRUE,
+        'show_text' => ts('to select someone already in our database'),
+        'hide_text' => ts('to clear this person and fill the form in for someone else'),
+        'url' => array('civicrm/ajax/rest', 'className=CRM_Contact_Page_AJAX&fnName=getContactList&json=1'),
+        'max' => civicrm_api3('setting', 'getvalue', array(
+        'name' => 'search_autocomplete_count',
+        'group' => 'Search Preferences',
+        ))
+      ), $autoCompleteField);
+
+    if(0 < (civicrm_api3('contact', 'getcount', array('check_permissions' => 1)))) {
+      $this->addElement('text', $autoCompleteField['name_field'] , $autoCompleteField['field_text']);
+      $this->addElement('hidden',  $autoCompleteField['id_field'], '', array('id' => $autoCompleteField['id_field']));      $this->assign('selectable', $autoCompleteField['id_field']);
+
+      CRM_Core_Resources::singleton()->addScriptFile('civicrm', 'templates/CRM/common/AutoComplete.js')
+      ->addSetting(array(
+      'form' => array('autocompletes' => $autoCompleteField),
+      'ids' => array('profile' => $profiles),
+      ));
+    }
+  }
+
+  /**
+   * Add the options appropriate to cid = zero - ie. autocomplete
+   *
+   * @todo there is considerable code duplication between the contribution forms & event forms. It is apparent
+   * that small pieces of duplication are not being refactored into separate functions because their only shared parent
+   * is this form. Inserting a class FrontEndForm.php between the contribution & event & this class would allow functions like this
+   * and a dozen other small ones to be refactored into a shared parent with the reduction of much code duplication
+   */
+  function addCIDZeroOptions($onlinePaymentProcessorEnabled) {
+    $this->assign('nocid', TRUE);
+    $profiles = array();
+    if($this->_values['custom_pre_id']) {
+      $profiles[] = $this->_values['custom_pre_id'];
+    }
+    if($this->_values['custom_post_id']) {
+      $profiles[] = $this->_values['custom_post_id'];
+    }
+    if($onlinePaymentProcessorEnabled) {
+      $profiles[] = 'billing';
+    }
+    if(!empty($this->_values)) {
+      $this->addAutoSelector($profiles);
+    }
+  }
 }
 
index b4d526b3ddb48d7aafa7e256f6fc2ebaa86779f9..be8e3ca65a837e86dc47331a1ba5ad6fbc0eac43 100644 (file)
@@ -426,14 +426,20 @@ class CRM_Event_Form_Registration_Register extends CRM_Event_Form_Registration {
       self::buildAmount($this);
     }
 
-    $pps = NULL;
+    $pps = array();
+    //@todo this processor adding fn is another one duplicated on contribute - a shared
+    // common class would make this sort of thing extractable
     if (!empty($this->_paymentProcessors)) {
-      $pps = $this->_paymentProcessors;
-      foreach ($pps as $key => & $name) {
+      foreach ($this->_paymentProcessors as $key => $name) {
+        if($name['billing_mode'] == 1) {
+          $onlinePaymentProcessorEnabled = TRUE;
+        }
         $pps[$key] = $name['name'];
       }
     }
-
+    if($this->getContactID() === '0') {
+      $this->addCidZeroOptions($onlinePaymentProcessorEnabled);
+    }
     if (CRM_Utils_Array::value('is_pay_later', $this->_values['event']) &&
       ($this->_allowConfirmation || (!$this->_requireApproval && !$this->_allowWaitlist))
     ) {
index 4195822e4cbfddf455aa1a15ab3f8b2c8a2c7969..a64ccd3cc2bfab74b2a931a3d84768ea67378faa 100644 (file)
@@ -53,7 +53,7 @@
     {/if}
   {/if}
 
-{* Main Form *}  
+{* Main Form *}
 {else}
   {literal}
   <script type="text/javascript">
@@ -99,6 +99,7 @@
   <div id="intro_text" class="crm-section intro_text-section">
     {$intro_text}
   </div>
+  {include file="CRM/common/cidzero.tpl"}
   {if $islifetime or $ispricelifetime }
   <div id="help">{ts}You have a current Lifetime Membership which does not need to be renewed.{/ts}</div>
   {/if}
index 635a6461e7e4c8b486748aaecb72621e7ecd5006..7a99f40413d32c8e7ff2f3d7ebc39cf2db7f8a37 100644 (file)
@@ -44,7 +44,6 @@
 {/if}
 
 {include file="CRM/common/TrackingFields.tpl"}
-
 {capture assign='reqMark'}<span class="marker"  title="{ts}This field is required.{/ts}">*</span>{/capture}
 <div class="crm-event-id-{$event.id} crm-block crm-event-register-form-block">
 
@@ -69,7 +68,7 @@
         <p>{$event.intro_text}</p>
     </div>
 {/if}
-
+{include file="CRM/common/cidzero.tpl"}
 {if $pcpSupporterText}
     <div class="crm-section pcpSupporterText-section">
         <div class="content">{$pcpSupporterText}</div>
diff --git a/templates/CRM/common/AutoComplete.js b/templates/CRM/common/AutoComplete.js
new file mode 100644 (file)
index 0000000..0077542
--- /dev/null
@@ -0,0 +1,141 @@
+/**
+ * This is our closure - all of our code goes inside it
+ *
+ * This style of closure is provided by jquery and automatically
+ * waits for document.ready. It also provides us with a local
+ * alias of jQuery as $.
+ *
+ * ES5 specifies that the first line inside our closure
+ * should be 'use strict';
+ */
+/*jslint indent: 2 */
+/*global CRM, cj, ts */
+
+cj(function ($) {
+  'use strict';
+
+  // Variables declared here will be globally available within this closure
+
+  // Behind the scenes method deals with browser for setting cursor position
+  $.caretTo = function (el, index) {
+    if (el.createTextRange) {
+      var range = el.createTextRange();
+      range.move("character", index);
+      range.select();
+    }
+    else if (el.selectionStart != null) {
+      el.focus();
+      el.setSelectionRange(index, index);
+    }
+  };
+
+  //The following methods are queued under fx for more
+  //flexibility when combining with $.fn.delay() and
+  //jQuery effects.
+
+  //Set caret to a particular index
+  $.fn.caretTo = function (index, offset) {
+    return this.queue(function (next) {
+      if (isNaN(index)) {
+        var i = $(this).val().indexOf(index);
+        if (offset === true) {
+          i += index.length;
+        }
+        else if (offset) {
+          i += offset;
+        }
+        $.caretTo(this, i);
+      }
+      else {
+        $.caretTo(this, index);
+      }
+      next();
+    });
+};
+
+  /**
+   * Display a personalized message containing the contact's name
+   * and a variable from the server
+   */
+  function assignAutoComplete(select_field, id_field, url, varmax, profileids, autocomplete) {
+    if(varmax === undefined) {varmax = 10;}
+    if(profileids === undefined) {profileids = [];}
+
+    if(url === undefined) {
+      url = CRM.url('civicrm/ajax/rest', 'className=CRM_Contact_Page_AJAX&fnName=getContactList&json=1');
+    }
+
+    var customObj   = $('#' + select_field);
+    var customIdObj = $('#' + id_field);
+
+    if (!customObj.hasClass('ac_input')) {
+      customObj.autocomplete(url,
+        { width : 250, selectFirst : false, matchContains: true, max: varmax }).result(
+        function (event, data) {
+          customIdObj.val(data[1]);
+          customObj.caretTo(0);
+          var namefields = ['first_name', 'last_name', 'middle_name'];
+          CRM.api('profile', 'get', {'profile_id' : profileids, 'contact_id' : data[1]}, {
+            success: function(result) {
+              $.each(result.values, function (id, values){
+              $.each(values, function (fieldname, fieldvalue) {
+                $('#' + fieldname).val(fieldvalue);
+              });
+              });
+            }
+          });
+        }
+      );
+      customObj.click(function () {
+        customIdObj.val('');
+      });
+    }
+    
+    if(autocomplete.show_hide) {
+      customObj.hide();
+      showHideAutoComplete(select_field, id_field,
+        autocomplete.show_text,
+        autocomplete.hide_text,
+        profileids
+      );
+    }
+  }
+  
+  /**
+   * Show or hide the autocomplete and change the text
+   */
+  function showHideAutoComplete(name_field, id_field, hidden_text, shown_text, profileids) {
+    $('#crm-contact-toggle-' + id_field).on('click', function(event) {
+      event.preventDefault();
+      $('#' + name_field).toggle();
+      if($('#' + name_field).is(":visible")) {
+        $('#crm-contact-toggle-text-'  + id_field).text(shown_text);
+      }
+      else{
+        $('#crm-contact-toggle-text-'  + id_field).text(hidden_text);
+        $('#' + id_field).val('');
+        CRM.api('profile', 'get', {'profile_id' : profileids}, {
+          success: function(result) {
+            $.each(result.values, function (id, values){
+            $.each(values, function (fieldname, fieldvalue) {
+              $('#' + fieldname).val(fieldvalue);
+            });
+            });
+          }
+        });
+      }
+
+    });
+    //  append(ts("Click") + " <a href='#' id= crm-contact-toggle-" + autocomplete.id_field + ("> " +  ts('here') + '</a> ' + ts("to clear this and add a new contact"));
+  }
+
+  var autocompletes = CRM.form.autocompletes;
+  var url = CRM.url(autocompletes.url[0], autocompletes.url[1]);
+
+  $(autocompletes).each(function (index, autocomplete) {
+    assignAutoComplete(autocomplete.name_field, autocomplete.id_field, url, autocomplete.max, CRM.ids.profile, autocomplete);
+    }
+  );
+
+});
+
diff --git a/templates/CRM/common/cidzero.tpl b/templates/CRM/common/cidzero.tpl
new file mode 100644 (file)
index 0000000..cda2fd9
--- /dev/null
@@ -0,0 +1,16 @@
+  <div class="crm-create-relationship-row">
+  {if !empty($nocid)}
+    <span>{ts}You are entering this form on behalf of someone else. Please enter their details.</span>{/ts}
+  {/if}
+  {if !empty($selectable)}
+    {ts} <p> Click <a href=# id='crm-contact-toggle-{$selectable}'>here</a>
+     <span id='crm-contact-toggle-text-{$selectable}'> to select someone already in our database</span></p>{/ts}
+    <span id='crm-contact-toggle-hidden-text-{$selectable}'>
+    </span>
+    <div class="crm-contact-select-row">
+      <div class="crm-content">
+        {$form.select_contact.html}
+      </div>
+    </div>
+  {/if}
+  </div>