Merge pull request #6539 from joannechester/CRM-16185-rename-date-filters
[civicrm-core.git] / CRM / Core / Payment / PayPalImpl.php
index 7a6f58e0381db703828c92303a2a49925ae5d15f..a811b096758ec8723ad2d4ed4bf298c76d2bfe7c 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 /*
  +--------------------------------------------------------------------+
- | CiviCRM version 4.6                                                |
+ | CiviCRM version 4.7                                                |
  +--------------------------------------------------------------------+
  | Copyright CiviCRM LLC (c) 2004-2015                                |
  +--------------------------------------------------------------------+
@@ -124,7 +124,7 @@ class CRM_Core_Payment_PayPalImpl extends CRM_Core_Payment {
    * Billing mode button is basically synonymous with paypal express  - this is probably a good example of 'odds & sods' code we
    * need to find a way for the payment processor to assign. A tricky aspect is that the payment processor may need to set the order
    *
-   * @param $form
+   * @param CRM_Core_Form $form
    */
   protected function addPaypalExpressCode(&$form) {
     if (empty($form->isBackOffice)) {
@@ -155,6 +155,21 @@ class CRM_Core_Payment_PayPalImpl extends CRM_Core_Payment {
     return TRUE;
   }
 
+  /**
+   * Default payment instrument validation.
+   *
+   * Implement the usual Luhn algorithm via a static function in the CRM_Core_Payment_Form if it's a credit card
+   * Not a static function, because I need to check for payment_type.
+   *
+   * @param array $values
+   * @param array $errors
+   */
+  public function validatePaymentInstrument($values, &$errors) {
+    if ($this->_paymentProcessor['payment_processor_type'] == 'PayPal_Pro') {
+      CRM_Core_Payment_Form::validateCreditCard($values, $errors);
+    }
+  }
+
   /**
    * Express checkout code. Check PayPal documentation for more information
    *
@@ -266,7 +281,7 @@ class CRM_Core_Payment_PayPalImpl extends CRM_Core_Payment {
    *   the result in an nice formatted array (or an error object)
    */
   public function doExpressCheckout(&$params) {
-
+    $statuses = CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id');
     if (!empty($params['is_recur'])) {
       return $this->createRecurringPayments($params);
     }
@@ -289,7 +304,7 @@ class CRM_Core_Payment_PayPalImpl extends CRM_Core_Payment {
     $result = $this->invokeAPI($args);
 
     if (is_a($result, 'CRM_Core_Error')) {
-      return $result;
+      throw new PaymentProcessorException(CRM_Core_Error::getMessages($result));
     }
 
     /* Success */
@@ -303,7 +318,13 @@ class CRM_Core_Payment_PayPalImpl extends CRM_Core_Payment {
     }
     $params['payment_status'] = $result['paymentstatus'];
     $params['pending_reason'] = $result['pendingreason'];
-
+    if (!empty($params['is_recur'])) {
+      // See comment block.
+      $result['payment_status_id'] = array_search('Pending', $statuses);
+    }
+    else {
+      $result['payment_status_id'] = array_search('Completed', $statuses);
+    }
     return $params;
   }
 
@@ -380,6 +401,39 @@ class CRM_Core_Payment_PayPalImpl extends CRM_Core_Payment {
     $args['method'] = $method;
   }
 
+  /**
+   * Process payment - this function wraps around both doTransferPayment and doDirectPayment.
+   *
+   * 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 payment_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.
+   *
+   * Once this function is fully rolled out then it will be preferred for processors to throw exceptions than to
+   * return Error objects
+   *
+   * @param array $params
+   *
+   * @param string $component
+   *
+   * @return array
+   *   Result array
+   *
+   * @throws \Civi\Payment\Exception\PaymentProcessorException
+   */
+  public function doPayment(&$params, $component = 'contribute') {
+    if ($this->_paymentProcessor['payment_processor_type'] != 'PayPal_Express') {
+      return parent::doPayment($params, $component);
+    }
+    $this->_component = $component;
+    return $this->doExpressCheckout($params);
+  }
+
   /**
    * This function collects all the information from a web/api form and invokes
    * the relevant payment processor specific functions to perform the transaction
@@ -462,9 +516,42 @@ class CRM_Core_Payment_PayPalImpl extends CRM_Core_Payment {
 
     $params['trxn_id'] = CRM_Utils_Array::value('transactionid', $result);
     $params['gross_amount'] = CRM_Utils_Array::value('amt', $result);
+    $params = array_merge($params, $this->doQuery($params));
     return $params;
   }
 
+  /**
+   * Query payment processor for details about a transaction.
+   *
+   * For paypal see : https://developer.paypal.com/webapps/developer/docs/classic/api/merchant/GetTransactionDetails_API_Operation_NVP/
+   *
+   * @param array $params
+   *   Array of parameters containing one of:
+   *   - trxn_id Id of an individual transaction.
+   *   - processor_id Id of a recurring contribution series as stored in the civicrm_contribution_recur table.
+   *
+   * @return array
+   *   Extra parameters retrieved.
+   *   Any parameters retrievable through this should be documented in the function comments at
+   *   CRM_Core_Payment::doQuery. Currently
+   *   - fee_amount Amount of fee paid
+   *
+   * @throws \Civi\Payment\Exception\PaymentProcessorException
+   */
+  public function doQuery($params) {
+    if (empty($params['trxn_id'])) {
+      throw new \Civi\Payment\Exception\PaymentProcessorException('transaction id not set');
+    }
+    $args = array(
+      'TRANSACTIONID' => $params['trxn_id'],
+    );
+    $this->initialize($args, 'GetTransactionDetails');
+    $result = $this->invokeAPI($args);
+    return array(
+      'fee_amount' => $result['feeamt'],
+    );
+  }
+
   /**
    * This function checks to see if we have the right config values.
    *