From 38621a92424f76ca99471b4885e1bcaf028b1b27 Mon Sep 17 00:00:00 2001
From: Peter Hartmann <peter@hartmanncomputer.com>
Date: Thu, 9 Mar 2017 03:43:37 -0500
Subject: [PATCH] put #155 to bed, extend Core Form

---
 CRM/Core/Form/Stripe.php    |  16 +++++
 CRM/Core/Payment/Stripe.php | 113 +++++++++++++++---------------------
 js/civicrm_stripe.js        |  38 ++++++------
 stripe.php                  |  30 +++++-----
 4 files changed, 98 insertions(+), 99 deletions(-)
 create mode 100644 CRM/Core/Form/Stripe.php

diff --git a/CRM/Core/Form/Stripe.php b/CRM/Core/Form/Stripe.php
new file mode 100644
index 00000000..828e2ea5
--- /dev/null
+++ b/CRM/Core/Form/Stripe.php
@@ -0,0 +1,16 @@
+<?php
+
+/*
+ * Form Class for Stripe
+ */
+
+class CRM_Core_Form_Stripe extends CRM_Core_Form {
+
+  /**
+   * Function to access protected payProcessors array in event registraion forms
+   */
+  public static function get_ppids(&$form) {
+    $payprocessorIds = $form->_paymentProcessors;
+    return $payprocessorIds;
+  }
+}
diff --git a/CRM/Core/Payment/Stripe.php b/CRM/Core/Payment/Stripe.php
index f7e2214d..68c5407d 100644
--- a/CRM/Core/Payment/Stripe.php
+++ b/CRM/Core/Payment/Stripe.php
@@ -231,30 +231,20 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
     return $return;
   }
 
-  /**
-   * Implementation of hook_civicrm_validateForm().
-   *
-   * Prevent server validation of cc fields
-   *
-   * @param $formName - the name of the form
-   * @param $fields - Array of name value pairs for all 'POST'ed form values
-   * @param $files - Array of file properties as sent by PHP POST protocol
-   * @param $form - reference to the form object
-   * @param $errors - Reference to the errors array.
-   *
-   */
-
   /**
    * Implementation of hook_civicrm_buildForm().
    *
    * @param $form - reference to the form object
    */
   public function buildForm(&$form) {
-    $stripe_key = self::stripe_get_key($form);
-    // If this is not a form Stripe is involved in, do nothing.
-    if (empty($stripe_key)) {
-      return;
-    }
+    $stripe_ppid = self::get_stripe_ppid($form);
+
+    // Add the ID to our form so our js can tell if Stripe has been selected.
+    $form->addElement('hidden', 'stripe_id', $stripe_ppid, array('id' => 'stripe-id'));
+
+    $stripe_key = self::stripe_get_key($stripe_ppid);
+    $form->addElement('hidden', 'stripe_pub_key', $stripe_key, array('id' => 'stripe-pub-key'));
+
     $params = $form->get('params');
     // Contrib forms store this in $params, Event forms in $params[0].
     if (!empty($params[0]['stripe_token'])) {
@@ -267,7 +257,15 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
       $form->setAttribute('class', $form->getAttribute('class') . ' stripe-payment-form');
       $form->addElement('hidden', 'stripe_token', $stripe_token, array('id' => 'stripe-token'));
     }
-    self::stripe_add_stripe_js($stripe_key, $form);
+
+    // Add the Civi version so we can accommodate different versions in civicrm_stripe.js.
+    if (self::get_civi_version() <= '4.7.0') {
+      $ext_mode = 1;
+    }
+    else {
+      $ext_mode = 2;
+    }
+    $form->addElement('hidden', 'ext_mode', $ext_mode, array('id' => 'ext-mode'));
 
     // Add email field as it would usually be found on donation forms.
     if (!isset($form->_elementIndex['email']) && !empty($form->userEmail)) {
@@ -275,74 +273,59 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
     }
   }
 
-  /**
-   * Return the stripe api public key (aka password)
-   *
-   * If this form could conceiveably now or at any time in the future
-   * contain a Stripe payment processor, return the api public key for
-   * that processor.
-   */
-  public static function stripe_get_key($form) {
+ public static function get_stripe_ppid($form) {
     if (empty($form->_paymentProcessor)) {
       return;
     }
-    // Only return first value if Stripe is the only/default.
-    if ($form->_paymentProcessor['payment_processor_type'] == 'Stripe') {
-      if (isset($form->_paymentProcessor['password'])) {
-        return $form->_paymentProcessor['password'];
-      }
+    // Determine if we are dealing with a webform in CiviCRM 4.7.  Those don't have a
+    //  _paymentProcessors array and only have one payprocesssor.
+    if (get_class($form) == 'CRM_Financial_Form_Payment') {
+      return $stripe_ppid = $form->_paymentProcessor['id'];
     }
-
-    // Otherwise we need to look through all active payprocs and find Stripe.
-    $is_test = 0;
-    if (isset($form->_mode)) {
-      $is_test = $form->_mode == 'live' ? 0 : 1;
-    }
-
-    // The _paymentProcessors array seems to be the most reliable way to find
-    // if the form is using Stripe.
-    if (!empty($form->_paymentProcessors)) {
-      foreach ($form->_paymentProcessors as $pp) {
-        if ($pp['payment_processor_type'] == 'Stripe') {
-          if (!empty($pp['password'])) {
-            return $pp['password'];
-          }
-          // We have a match.
-          return self::stripe_get_key_for_name($pp['name'], $is_test);
+    else {
+      // Find a Stripe pay processor ascociated with this Civi form and find the ID.
+   //   $payProcessors = $form->_paymentProcessors;
+      $payProcessors = CRM_Core_Form_Stripe::get_ppids($form);
+      foreach ($payProcessors as $payProcessor) {
+        if ($payProcessor['class_name'] == 'Payment_Stripe') {
+          return $stripe_ppid = $payProcessor['id'];
+          break;
         }
       }
     }
-    // Return NULL if this is not a form with Stripe involved.
-    return NULL;
+    // None of the payprocessors are Stripe.
+    if (empty($stripe_ppid)) {
+      return;
+    }
   }
 
   /**
-   * Given a payment processor name, return the pub key.
+   * Given a payment processor id, return the pub key.
    */
-  public function stripe_get_key_for_name($name, $is_test) {
+  public function stripe_get_key($stripe_ppid) {
     try {
-      $params = array('name' => $name, 'is_test' => $is_test);
-      $results = civicrm_api3('PaymentProcessor', 'get', $params);
-      if ($results['count'] == 1) {
-        $result = array_pop($results['values']);
-        return $result['password'];
-      }
+      $result = civicrm_api3('PaymentProcessor', 'getvalue', array(
+        'return' => "password",
+        'id' => $stripe_ppid,
+      ));
     }
     catch (CiviCRM_API3_Exception $e) {
       return NULL;
     }
+    return $result;
   }
 
   /**
-   * Add publishable key and event bindings for Stripe.js.
+   * Return the CiviCRM version we're running.
    */
-  public function stripe_add_stripe_js($stripe_key, $form) {
-    $form->addElement('hidden', 'stripe_pub_key', $stripe_key, array('id' => 'stripe-pub-key'));
-    CRM_Core_Resources::singleton()->addScriptFile('com.drastikbydesign.stripe', 'js/civicrm_stripe.js', 0);
+  public function get_civi_version() {
+    $version = civicrm_api3('Domain', 'getvalue', array(
+      'return' => "version",
+      'current_domain' => true,
+    ));
+    return $version;
   }
 
-
-
   /**
    * Submit a payment using Stripe's PHP API:
    * https://stripe.com/docs/api?lang=php
diff --git a/js/civicrm_stripe.js b/js/civicrm_stripe.js
index d7185161..a18bf887 100644
--- a/js/civicrm_stripe.js
+++ b/js/civicrm_stripe.js
@@ -117,7 +117,7 @@
     $form.submit(function (event) {
       // Don't handle submits generated by the CiviDiscount button.
       if ($form.data('cividiscount-dont-handle') == 1) {
-        debugging('pvjwy');
+        debugging('debug: pvjwy (Discount is in play)');
         return true;
       }
       if (isWebform) {
@@ -156,47 +156,45 @@
           if (currentTotal == 0 && !additionalParticipants) {
             // This is also hit when "Going back", but we already have stripe_token.
             debugging('ozlkf');
-            return true;
+            // This should not happen on Confirm Contribution, but seems to on 4.6 for some reason.
+            //return true;
           }
         }
       }
 
       // Handle multiple payment options and Stripe not being chosen.
       if ($form.find(".crm-section.payment_processor-section").length > 0) {
+        var extMode = $('#ext-mode').val();
+        var stripeProcessorId = $('#stripe-id').val();
         // Support for CiviCRM 4.6 and 4.7 multiple payment options
-        if (($form.find('input[name="payment_processor"]:checked').length) || ($form.find('input[name="payment_processor_id"]:checked').length)) {
-          processorId = $form.find(('input[name="payment_processor"]:checked')||('input[name="payment_processor_id"]:checked').val());
-          if (!($form.find('input[name="stripe_token"]').length) || ($('#stripe-id').length && $('#stripe-id').val() != processorId)) {
-            debugging('kfoej');
-            return true;
-          }
+        if (extMode == 1) {
+          var chosenProcessorId = $form.find('input[name="payment_processor"]:checked').val();
+        }
+        else if (extMode == 2) {
+          var chosenProcessorId = $form.find('input[name="payment_processor_id"]:checked').val();
         }
-        else {
-          // No payment processor is checked.
-          debugging('qlmvy');
+        // Bail if we're not using Stripe or are using pay later (option value '0' in payment_processor radio group).
+        if ((chosenProcessorId != stripeProcessorId) || (chosenProcessorId == 0)) {
+          debugging('debug: kfoej (Not a Stripe transaction, or pay-later)');
           return true;
         }
       }
-
-      // Handle pay later (option value '0' in payment_processor radio group).
-      if (($form.find('input[name="payment_processor"]:checked').length && !parseInt($form.find('input[name="payment_processor"]:checked').val()))
-        || ($form.find('input[name="payment_processor_id"]:checked').length && !parseInt($form.find('input[name="payment_processor_id"]:checked').val()))) { 
-        debugging('ynhpz');
-        return true;
+      else {
+          debugging('debug: qlmvy (Stripe is the only payprocessor here)');
       }
 
       // Handle reuse of existing token
       if ($form.find("input#stripe-token").val()) {
         $form.find("input#credit_card_number").removeAttr('name');
         $form.find("input#cvv2").removeAttr('name');
-        debugging('zpqef');
+        debugging('debug: zpqef (Re-using Stripe token)');
         return true;
       }
 
       // If there's no credit card field, no use in continuing (probably wrong
       // context anyway)
       if (!$form.find('#credit_card_number').length) {
-        debugging('gvzod');
+        debugging('debug: gvzod (No credit card field)');
         return true;
       }
 
@@ -221,7 +219,7 @@
         exp_year:    cc_year
       }, stripeResponseHandler);
 
-      debugging('ywkvh');
+      debugging('debug: ywkvh (Getting Stripe token)');
       return false;
     });
   });
diff --git a/stripe.php b/stripe.php
index ccb952df..f7701012 100644
--- a/stripe.php
+++ b/stripe.php
@@ -170,32 +170,34 @@ function stripe_civicrm_managed(&$entities) {
       return;
     }
     // If Stripe is active here.
-    if (isset($form->_elementIndex['stripe_token'])) {
-      if ($form->elementExists('credit_card_number')) {
-        $cc_field = $form->getElement('credit_card_number');
-        $form->removeElement('credit_card_number', true);
-        $form->addElement($cc_field);
-      }
-      if ($form->elementExists('cvv2')) {
-        $cvv2_field = $form->getElement('cvv2');
-        $form->removeElement('cvv2', true);
-        $form->addElement($cvv2_field);
+    if ($form->_paymentProcessor['class_name'] == 'Payment_Stripe') {
+      if (isset($form->_elementIndex['stripe_token'])) {
+        if ($form->elementExists('credit_card_number')) {
+          $cc_field = $form->getElement('credit_card_number');
+          $form->removeElement('credit_card_number', true);
+          $form->addElement($cc_field);
+        }
+        if ($form->elementExists('cvv2')) {
+          $cvv2_field = $form->getElement('cvv2');
+          $form->removeElement('cvv2', true);
+          $form->addElement($cvv2_field);
+        }
       }
+    } else {
+      return;
     }
   }
 
   /**
    * Implementation of hook_civicrm_alterContent
    *
+   * Adding civicrm_stripe.js in a way that works for webforms and Civi forms.
+   *
    * @return void
    */
   function stripe_civicrm_alterContent( &$content, $context, $tplName, &$object ) {
     if($context == 'form' && !empty($object->_paymentProcessor['class_name'])) {
       if($object->_paymentProcessor['class_name'] == 'Payment_Stripe') {
-        $stripe_key = CRM_Core_Payment_Stripe::stripe_get_key($object);
-        if(empty($stripe_key)) {
-        return;
-        }
         $stripeJSURL = CRM_Core_Resources::singleton()->getUrl('com.drastikbydesign.stripe', 'js/civicrm_stripe.js');
         $content .= "<script src='{$stripeJSURL}'></script>";
       }
-- 
GitLab