CRM-16555 move paypal code addition to buildForm
[civicrm-core.git] / CRM / Core / Payment.php
index 7a72e8e88d32208512074e979f2297ca73bd542a..3a35c663eb5de0adb84350bc88241653fc743491 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.                                    |
  |                                                                    |
@@ -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.
    *
@@ -206,6 +237,27 @@ abstract class CRM_Core_Payment {
     }
   }
 
+  /**
+   * Getter for the payment processor.
+   *
+   * The payment processor array is based on the civicrm_payment_processor table entry.
+   *
+   * @return array
+   *   Payment processor array.
+   */
+  public function getPaymentProcessor() {
+    return $this->_paymentProcessor;
+  }
+
+  /**
+   * Setter for the payment processor.
+   *
+   * @param array $processor
+   */
+  public function setPaymentProcessor($processor) {
+    $this->_paymentProcessor = $processor;
+  }
+
   /**
    * Setter for the payment form that wants to use the processor.
    *
@@ -460,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;
   }
 
@@ -530,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();
@@ -551,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
@@ -599,10 +680,7 @@ abstract class CRM_Core_Payment {
       }
       else {
         // Legacy or extension as module instance
-        if (empty($paymentClass)) {
-          $paymentClass = 'CRM_Core_' . $dao->class_name;
-
-        }
+        $paymentClass = 'CRM_Core_' . $dao->class_name;
       }
 
       $processorInstance = Civi\Payment\System::singleton()->getById($dao->processor_id);
@@ -646,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.
    *