CRM-16555 move paypal code addition to buildForm
[civicrm-core.git] / CRM / Core / Payment.php
index 81774bdfc2eb13f335d418ab8f53458d7ad4560d..3a35c663eb5de0adb84350bc88241653fc743491 100644 (file)
@@ -26,6 +26,7 @@
  */
 
 use Civi\Payment\System;
+use Civi\Payment\Exception\PaymentProcessorException;
 
 /**
  * Class CRM_Core_Payment.
@@ -89,7 +90,7 @@ abstract class CRM_Core_Payment {
    * @return CRM_Core_Payment
    * @throws \CRM_Core_Exception
    */
-  public static function &singleton($mode = 'test', &$paymentProcessor, &$paymentForm = NULL, $force = FALSE) {
+  public static function singleton($mode = 'test', &$paymentProcessor, &$paymentForm = NULL, $force = FALSE) {
     // make sure paymentProcessor is not empty
     // CRM-7424
     if (empty($paymentProcessor)) {
@@ -101,6 +102,18 @@ abstract class CRM_Core_Payment {
     return $object;
   }
 
+  /**
+   * Opportunity for the payment processor to override the entire form build.
+   *
+   * @param CRM_Core_Form $form
+   *
+   * @return bool
+   *   Should form building stop at this point?
+   */
+  public function buildForm(&$form) {
+     return FALSE;
+  }
+
   /**
    * Log payment notification message to forensic system log.
    *
@@ -162,6 +175,24 @@ abstract class CRM_Core_Payment {
     }
   }
 
+  /**
+   * Can more than one transaction be processed at once?
+   *
+   * In general processors that process payment by server to server communication support this while others do not.
+   *
+   * In future we are likely to hit an issue where this depends on whether a token already exists.
+   *
+   * @return bool
+   */
+  protected function supportsMultipleConcurrentPayments() {
+    if ($this->_paymentProcessor['billing_mode'] == 4 || $this->_paymentProcessor['payment_type'] != 1) {
+      return FALSE;
+    }
+    else {
+      return TRUE;
+    }
+  }
+
   /**
    * Are live payments supported - e.g dummy doesn't support this.
    *
@@ -481,25 +512,45 @@ abstract class CRM_Core_Payment {
    * The function ensures an exception is thrown & moves some of this logic out of the form layer and makes the forms
    * more agnostic.
    *
+   * Payment processors should set contribution_status_id. This function adds some historical defaults ie. the
+   * assumption that if a 'doDirectPayment' processors comes back it completed the transaction & in fact
+   * doTransferCheckout would not traditionally come back.
+   *
+   * doDirectPayment does not do an immediate payment for Authorize.net or Paypal so the default is assumed
+   * to be Pending.
+   *
    * @param array $params
    *
-   * @param $component
+   * @param string $component
    *
    * @return array
-   *   (modified)
-   * @throws CRM_Core_Exception
+   *   Result array
+   *
+   * @throws \Civi\Payment\Exception\PaymentProcessorException
    */
   public function doPayment(&$params, $component = 'contribute') {
+    $statuses = CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id');
     if ($this->_paymentProcessor['billing_mode'] == 4) {
       $result = $this->doTransferCheckout($params, $component);
+      if (is_array($result) && !isset($result['contribution_status_id'])) {
+        $result['contribution_status_id'] = array_search('Pending', $statuses);
+      }
     }
     else {
       $result = $this->doDirectPayment($params, $component);
+      if (is_array($result) && !isset($result['contribution_status_id'])) {
+        if (!empty($params['is_recur'])) {
+          // See comment block.
+          $paymentParams['contribution_status_id'] = array_search('Pending', $statuses);
+        }
+        else {
+          $result['contribution_status_id'] = array_search('Completed', $statuses);
+        }
+      }
     }
     if (is_a($result, 'CRM_Core_Error')) {
-      throw new CRM_Core_Exception(CRM_Core_Error::getMessages($result));
+      throw new PaymentProcessorException(CRM_Core_Error::getMessages($result));
     }
-    //CRM-15767 - Submit Credit Card Contribution not being saved
     return $result;
   }
 
@@ -551,6 +602,7 @@ abstract class CRM_Core_Payment {
         'processor_name' => @$_GET['processor_name'],
         'processor_id' => @$_GET['processor_id'],
         'mode' => @$_GET['mode'],
+        'q' => @$_GET['q'],
       )
     );
     CRM_Utils_System::civiExit();
@@ -572,8 +624,16 @@ abstract class CRM_Core_Payment {
    */
   public static function handlePaymentMethod($method, $params = array()) {
     if (!isset($params['processor_id']) && !isset($params['processor_name'])) {
-      CRM_Core_Error::fatal("Either 'processor_id' or 'processor_name' param is required for payment callback");
+      $q = explode('/', CRM_Utils_Array::value('q', $params, ''));
+      $lastParam = array_pop($q);
+      if (is_numeric($lastParam)) {
+        $params['processor_id'] = $_GET['processor_id'] = $lastParam;
+      }
+      else {
+        throw new CRM_Core_Exception("Either 'processor_id' or 'processor_name' param is required for payment callback");
+      }
     }
+
     self::logPaymentNotification($params);
 
     $sql = "SELECT ppt.class_name, ppt.name as processor_name, pp.id AS processor_id
@@ -664,6 +724,17 @@ abstract class CRM_Core_Payment {
     return method_exists(CRM_Utils_System::getClassName($this), $method);
   }
 
+  /**
+   * Some processors replace the form submit button with their own.
+   *
+   * Returning false here will leave the button off front end forms.
+   *
+   * At this stage there is zero cross-over between back-office processors and processors that suppress the submit.
+   */
+  public function isSuppressSubmitButtons() {
+    return FALSE;
+  }
+
   /**
    * Get url for users to manage this recurring contribution for this processor.
    *