CRM-15555 fix QA bug on paylater when billing option is required
authorEileen McNaughton <eileen@fuzion.co.nz>
Sat, 8 Nov 2014 07:42:10 +0000 (20:42 +1300)
committerEileen McNaughton <eileen@fuzion.co.nz>
Thu, 13 Nov 2014 15:04:39 +0000 (04:04 +1300)
CRM/Contribute/Form/AbstractEditPayment.php
CRM/Contribute/Form/Contribution/Main.php
CRM/Core/Payment/Form.php
CRM/Core/Payment/ProcessorForm.php

index 768730769faa7e9f6fc25dbc693995607c96ba41..1546dc51ee21c961620392487d9d88079be0a8a7 100644 (file)
@@ -142,7 +142,7 @@ class CRM_Contribute_Form_AbstractEditPayment extends CRM_Core_Form {
   public $_honorID = NULL;
 
   /**
-   * Store the contribution Type ID
+   * Store the financial Type ID
    *
    * @var array
    */
@@ -177,8 +177,23 @@ class CRM_Contribute_Form_AbstractEditPayment extends CRM_Core_Form {
   public $isBackOffice = TRUE;
 
   protected $_formType;
+
+  /**
+   * @var mystery variable screaming out for documentation
+   */
   protected $_cdType;
 
+  /**
+   * array of fields to display on billingBlock.tpl - this is not fully implemented but basically intent is the panes/fieldsets on this page should
+   * be all in this array in order like
+   *  'credit_card' => array('credit_card_number' ...
+   *  'billing_details' => array('first_name' ...
+   *
+   * such that both the fields and the order can be more easily altered by payment processors & other extensions
+   * @var array
+   */
+  public $billingFieldSets = array();
+
   /**
    * @param $id
    */
index 056ca1d192caa0fe9b405bb19636756969f9f367..0266fb3522492c2228b9e01373a77ef1d60a8a93 100644 (file)
@@ -56,6 +56,12 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu
 
   public $_useForMember;
 
+  /**
+   * array of payment related fields to potentially display on this form (generally credit card or debit card fields). Th
+   * @var array
+   */
+  public $_paymentFields = array();
+
   protected $_ppType;
   protected $_snippet;
 
index f5b4fbf08a461ef13368a0184dbc5b64b0781c48..b163c3f02684e37d31f2caefcac4faefb6191c74 100644 (file)
@@ -36,46 +36,58 @@ class CRM_Core_Payment_Form {
 
 
   /**
-   * Add payment fields are depending on payment processor
+   * Add payment fields depending on payment processor. The payment processor can implement the following functions to override the built in fields.
    *
-   * @param CRM_Contribute_Form_Contribution| CRM_Contribute_Form_Contribution_Main $form
-   * @todo - add other forms specifically to the definition - since we don't have for $form - since we aren't adding the property to
-   * CRM_Core_Form (don't suppose we should?)
+   *  - getPaymentFormFields()
+   *  - getPaymentFormFieldsMetadata()
+   *  (planned - getBillingDetailsFormFields(), getBillingDetailsFormFieldsMetadata()
+   *
+   *  Note that this code is written to accommodate the possibility CiviCRM will switch to implementing pay later as a manual processor in future
+   *
+   * @param CRM_Contribute_Form_AbstractEditPayment|CRM_Contribute_Form_Contribution_Main $form
    * @param array $processor array of properties including 'object' as loaded from CRM_Financial_BAO_PaymentProcessor::getPaymentProcessors
+   * @param bool $forceBillingFieldsForPayLater display billing fields even for pay later
    */
-  static public function setPaymentFieldsByProcessor(&$form, $processor) {
+  static public function setPaymentFieldsByProcessor(&$form, $processor, $forceBillingFieldsForPayLater = FALSE) {
     $form->billingFieldSets = array();
-    $paymentFields = self::getPaymentFields($processor);
-    $paymentTypeName = self::getPaymentTypeName($processor);
-    $paymentTypeLabel = self::getPaymentTypeLabel($processor);
-    //@todo if we switch to iterating through the fieldsets we won't need to assign these directly
-    $form->assign('paymentTypeName', $paymentTypeName);
-    $form->assign('paymentTypeLabel', $paymentTypeLabel);
-
-    $form->billingFieldSets[$paymentTypeName]['fields'] = $form->_paymentFields = array_intersect_key(self::getPaymentFieldMetadata($processor), array_flip($paymentFields));
-    $form->billingPane = array($paymentTypeName => $paymentTypeLabel);
-    $form->assign('paymentFields', $paymentFields);
-    if ($processor['billing_mode'] != 4) {
-      //@todo setPaymentFields defines the billing fields - this should be moved to the processor class & renamed getBillingFields
-      // currently we just add the standard lot unless it's an off-site processor (& then add none)
-      //also set the billingFieldSet to hold all the details required to render the fieldset so we can iterate through the fieldset - making
-      // it easier to re-order. For not the billingFieldSets param is used to determine whether to show the billing pane
-      CRM_Core_Payment_Form::_setPaymentFields($form);
-      $form->billingFieldSets['billing_name_address-group']['fields'] = array();
+    if ($processor != NULL) {
+      // ie it is pay later
+      $paymentFields = self::getPaymentFields($processor);
+      $paymentTypeName = self::getPaymentTypeName($processor);
+      $paymentTypeLabel = self::getPaymentTypeLabel($processor);
+      //@todo if we switch to iterating through $form->billingFieldSets we won't need to assign these directly
+      $form->assign('paymentTypeName', $paymentTypeName);
+      $form->assign('paymentTypeLabel', $paymentTypeLabel);
+
+      $form->billingFieldSets[$paymentTypeName]['fields'] = $form->_paymentFields = array_intersect_key(self::getPaymentFieldMetadata($processor), array_flip($paymentFields));
+      $form->billingPane = array($paymentTypeName => $paymentTypeLabel);
+      $form->assign('paymentFields', $paymentFields);
+    }
+
+    // @todo - replace this section with one similar to above per discussion - probably use a manual processor shell class to stand in for that capability
+    //return without adding billing fields if billing_mode = 4 (@todo - more the ability to set that to the payment processor)
+    // or payment processor is NULL (pay later)
+    if (($processor == NULL && !$forceBillingFieldsForPayLater) ||  $processor['billing_mode'] == 4) {
+      return;
     }
+    //@todo setPaymentFields defines the billing fields - this should be moved to the processor class & renamed getBillingFields
+    // potentially pay later would also be a payment processor
+    //also set the billingFieldSet to hold all the details required to render the fieldset so we can iterate through the fieldset - making
+    // it easier to re-order in hooks etc. The billingFieldSets param is used to determine whether to show the billing pane
+    CRM_Core_Payment_Form::setBillingDetailsFields($form);
+    $form->billingFieldSets['billing_name_address-group']['fields'] = array();
   }
 
   /**
    * add general billing fields
    * @todo set these like processor fields & let payment processors alter them
    *
-   *
    * @param $form
    *
    * @return void
    * @access protected
    */
-  static protected function _setPaymentFields(&$form) {
+  static protected function setBillingDetailsFields(&$form) {
     $bltID = $form->_bltID;
 
     $form->_paymentFields['billing_first_name'] = array(
@@ -173,7 +185,7 @@ class CRM_Core_Payment_Form {
    * @access public
    */
   static function setCreditCardFields(&$form) {
-    CRM_Core_Payment_Form::_setPaymentFields($form);
+    CRM_Core_Payment_Form::setBillingDetailsFields($form);
 
     $form->_paymentFields['credit_card_number'] = array(
       'htmlType' => 'text',
@@ -255,7 +267,7 @@ class CRM_Core_Payment_Form {
    * @access public
    */
   static function setDirectDebitFields(&$form) {
-    CRM_Core_Payment_Form::_setPaymentFields($form);
+    CRM_Core_Payment_Form::setBillingDetailsFields($form);
 
     $form->_paymentFields['account_holder'] = array(
       'htmlType' => 'text',
@@ -346,14 +358,29 @@ class CRM_Core_Payment_Form {
   }
 
   /**
-   * @param CRM_Contribute_Form_Contribution| CRM_Contribute_Form_Contribution_Main|CRM_Member_Form_Membership $form
+   * @param CRM_Contribute_Form_Contribution| CRM_Contribute_Form_Contribution_Main|CRM_Core_Payment_ProcessorForm $form
    * @param array $processor array of properties including 'object' as loaded from CRM_Financial_BAO_PaymentProcessor::getPaymentProcessors
-   * @param bool $isBillingDataOptional
+   * @param bool $isBillingDataOptional This manifests for 'NULL' (pay later) payment processor as the addition of billing fields to the form and
+   *   for payment processors that gather payment data on site as rendering the fields as not being required. (not entirely sure why but this
+   *   is implemented for back office forms)
    *
    * @return bool
    */
   static function buildPaymentForm($form, $processor, $isBillingDataOptional){
-    self::setPaymentFieldsByProcessor($form, $processor);
+    //if the form has address fields assign to the template so the js can decide what billing fields to show
+    $profileAddressFields = $form->get('profileAddressFields');
+    if (!empty($profileAddressFields)) {
+      $form->assign('profileAddressFields', $profileAddressFields);
+    }
+
+    // $processor->buildForm appears to be an undocumented (possibly unused) option for payment processors
+    // which was previously available only in some form flows
+    if (!empty($form->_paymentProcessor) && !empty($form->_paymentProcessor['object']) && $form->_paymentProcessor['object']->isSupported('buildForm')) {
+      $form->_paymentProcessor['object']->buildForm($form);
+      return;
+    }
+
+    self::setPaymentFieldsByProcessor($form, $processor, empty($isBillingDataOptional));
     self::addCommonFields($form, !$isBillingDataOptional, $form->_paymentFields);
     self::addRules($form, $form->_paymentFields);
     self::addPaypalExpressCode($form);
@@ -483,40 +510,6 @@ class CRM_Core_Payment_Form {
     }
   }
 
-  /**
-   * Function to add address block
-   *
-   * @param $form
-   * @param bool $useRequired
-   *
-   * @return void
-   * @access public
-   */
-  static function buildAddressBlock(&$form, $useRequired = FALSE) {
-    CRM_Core_Payment_Form::_setPaymentFields($form);
-    foreach ($form->_paymentFields as $name => $field) {
-      if (isset($field['cc_field']) &&
-        $field['cc_field']
-      ) {
-        $form->add($field['htmlType'],
-          $field['name'],
-          $field['title'],
-          $field['attributes'],
-          $useRequired ? $field['is_required'] : FALSE
-        );
-      }
-    }
-
-    // also take care of state country widget
-    $stateCountryMap = array(
-      1 => array(
-        'country' => "billing_country_id-{$form->_bltID}",
-        'state_province' => "billing_state_province_id-{$form->_bltID}",
-      )
-    );
-    CRM_Core_BAO_Address::addStateCountryMap($stateCountryMap);
-  }
-
   /**
    * Make sure that credit card number and cvv are valid
    * Called within the scope of a QF formRule function
index 3f2394be24b635ef83d06119b92098bf40c870c4..50bfabbdbc66053587d81c212305f921a537d665 100644 (file)
@@ -74,6 +74,7 @@ class CRM_Core_Payment_ProcessorForm {
     $form->assign_by_ref('paymentProcessor', $form->_paymentProcessor);
 
     // check if this is a paypal auto return and redirect accordingly
+    //@todo - determine if this is legacy and remove
     if (CRM_Core_Payment::paypalRedirect($form->_paymentProcessor)) {
       $url = CRM_Utils_System::url('civicrm/contribute/transact',
         "_qf_ThankYou_display=1&qfKey={$form->controller->_key}"
@@ -104,34 +105,9 @@ class CRM_Core_Payment_ProcessorForm {
    * @param $form
    */
   static function buildQuickform(&$form) {
+    //@todo document why this addHidden is here
     $form->addElement('hidden', 'hidden_processor', 1);
-
-    $profileAddressFields = $form->get('profileAddressFields');
-    if (!empty($profileAddressFields)) {
-      $form->assign('profileAddressFields', $profileAddressFields);
-    }
-
-    // check if show billing setting is enabled
-    if ($form->getVar( '_ppType' ) == 0 && $form->_isBillingAddressRequiredForPayLater) {
-      CRM_Core_Payment_Form::buildAddressBlock($form);
-      return;
-    }
-
-    // before we do this lets see if the payment processor has implemented a buildForm method
-    if (method_exists($form->_paymentProcessor['instance'], 'buildForm') &&
-      is_callable(array($form->_paymentProcessor['instance'], 'buildForm'))) {
-      // the payment processor implements the buildForm function, let the payment
-      // processor do the work
-      $form->_paymentProcessor['instance']->buildForm($form);
-      return;
-    }
-
-    if (($form->_paymentProcessor['payment_type'] & CRM_Core_Payment::PAYMENT_TYPE_DIRECT_DEBIT)) {
-      CRM_Core_Payment_Form::buildDirectDebit($form, TRUE);
-    }
-    elseif (($form->_paymentProcessor['payment_type'] & CRM_Core_Payment::PAYMENT_TYPE_CREDIT_CARD)) {
-      CRM_Core_Payment_Form::buildCreditCard($form, TRUE);
-    }
+    CRM_Core_Payment_Form::buildPaymentForm($form, $form->_paymentProcessor, empty($form->_isBillingAddressRequiredForPayLater));
   }
 }