CRM-15444 bring AuthorizenetIPN into line with PaypalIPN
authorEileen McNaughton <eileen@fuzion.co.nz>
Mon, 13 Oct 2014 02:25:57 +0000 (15:25 +1300)
committerEileen McNaughton <eileen@fuzion.co.nz>
Mon, 13 Oct 2014 02:30:56 +0000 (15:30 +1300)
CRM/Core/Payment/AuthorizeNetIPN.php
CRM/Core/Payment/PayPalProIPN.php
extern/authorizeIPN.php
tests/phpunit/CRM/Core/Payment/AuthorizeNetIPNTest.php [new file with mode: 0644]
tests/phpunit/CRM/Core/Payment/AuthorizeNetTest.php
tests/phpunit/CRM/Core/Payment/BaseIPNTest.php
tests/phpunit/CRM/Core/Payment/PayPalProIPNTest.php
tests/phpunit/CiviTest/CiviUnitTestCase.php

index 93c43e7fe2c94822f1bc3c955e53aa9af9eda68f..5597e6e04c1a7080992e62ae069003971b16ca2b 100644 (file)
  *
  */
 class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
+
   /**
-   * Constructor
+   * constructor function
+   *
+   * @param $inputData array contents of HTTP REQUEST
+   *
+   * @throws CRM_Core_Exception
    */
-  function __construct() {
+  function __construct($inputData) {
+    $this->setInputParameters($inputData);
     parent::__construct();
   }
 
@@ -49,7 +55,7 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
 
     //we only get invoice num as a key player from payment gateway response.
     //for ARB we get x_subscription_id and x_subscription_paynum
-    $x_subscription_id = self::retrieve('x_subscription_id', 'String');
+    $x_subscription_id = $this->retrieve('x_subscription_id', 'String');
 
     if ($x_subscription_id) {
       //Approved
@@ -80,12 +86,13 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
         return $this->recur($input, $ids, $objects, $first);
       }
     }
+    return TRUE;
   }
 
   /**
    * @param array $input
    * @param array $ids
-   * @param $objects
+   * @param array $objects
    * @param $first
    *
    * @return bool
@@ -219,14 +226,15 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
    * @param $ids
    */
   function getInput(&$input, &$ids) {
-    $input['amount'] = self::retrieve('x_amount', 'String');
-    $input['subscription_id'] = self::retrieve('x_subscription_id', 'Integer');
-    $input['response_code'] = self::retrieve('x_response_code', 'Integer');
-    $input['MD5_Hash'] = self::retrieve('x_MD5_Hash', 'String', FALSE, '');
-    $input['response_reason_code'] = self::retrieve('x_response_reason_code', 'String', FALSE);
-    $input['response_reason_text'] = self::retrieve('x_response_reason_text', 'String', FALSE);
-    $input['subscription_paynum'] = self::retrieve('x_subscription_paynum', 'Integer', FALSE, 0);
-    $input['trxn_id'] = self::retrieve('x_trans_id', 'String', FALSE);
+    $input['amount'] = $this->retrieve('x_amount', 'String');
+    $input['subscription_id'] = $this->retrieve('x_subscription_id', 'Integer');
+    $input['response_code'] = $this->retrieve('x_response_code', 'Integer');
+    $input['MD5_Hash'] = $this->retrieve('x_MD5_Hash', 'String', FALSE, '');
+    $input['response_reason_code'] = $this->retrieve('x_response_reason_code', 'String', FALSE);
+    $input['response_reason_text'] = $this->retrieve('x_response_reason_text', 'String', FALSE);
+    $input['subscription_paynum'] = $this->retrieve('x_subscription_paynum', 'Integer', FALSE, 0);
+    $input['trxn_id'] = $this->retrieve('x_trans_id', 'String', FALSE);
+
     if ($input['trxn_id']) {
       $input['is_test'] = 0;
     }
@@ -250,7 +258,7 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
       "email-{$billingID}" => 'x_email',
     );
     foreach ($params as $civiName => $resName) {
-      $input[$civiName] = self::retrieve($resName, 'String', FALSE);
+      $input[$civiName] = $this->retrieve($resName, 'String', FALSE);
     }
   }
 
@@ -259,8 +267,8 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
    * @param $input
    */
   function getIDs(&$ids, &$input) {
-    $ids['contact'] = self::retrieve('x_cust_id', 'Integer', FALSE, 0);
-    $ids['contribution'] = self::retrieve('x_invoice_num', 'Integer');
+    $ids['contact'] = $this->retrieve('x_cust_id', 'Integer', FALSE, 0);
+    $ids['contribution'] = $this->retrieve('x_invoice_num', 'Integer');
 
     // joining with contribution table for extra checks
     $sql = "
@@ -313,28 +321,25 @@ INNER JOIN civicrm_membership_payment mp ON m.id = mp.membership_id AND mp.contr
   }
 
   /**
-   * @param $name
-   * @param $type
-   * @param bool $abort
-   * @param null $default
-   * @param string $location
+   * @param string $name parameter name
+   * @param string $type parameter type
+   * @param bool $abort abort if not present
+   * @param null $default default value
    *
+   * @throws CRM_Core_Exception
    * @return mixed
    */
-  static function retrieve($name, $type, $abort = TRUE, $default = NULL, $location = 'POST') {
-    static $store = NULL;
-    $value = CRM_Utils_Request::retrieve($name, $type, $store,
-      FALSE, $default, $location
+  function retrieve($name, $type, $abort = TRUE, $default = NULL) {
+    $value = CRM_Utils_Type::validate(
+      empty($this->_inputParameters[$name]) ? $default : $this->_inputParameters[$name],
+      $type,
+      FALSE
     );
     if ($abort && $value === NULL) {
-      CRM_Core_Error::debug_log_message("Could not find an entry for $name in $location");
-      CRM_Core_Error::debug_var('POST', $_POST);
-      CRM_Core_Error::debug_var('REQUEST', $_REQUEST);
-      echo "Failure: Missing Parameter<p>";
-      exit();
+      throw new CRM_Core_Exception("Could not find an entry for $name");
     }
     return $value;
-  }
+}
 
   /**
    * @param $ids
index 6a8674917b9392b1d1cc36f9725feb014e81a464..d52e00e0a47f2296db8345e80010cfb815b96203 100644 (file)
@@ -59,8 +59,13 @@ class CRM_Core_Payment_PayPalProIPN extends CRM_Core_Payment_BaseIPN {
    * @var string component
    */
   protected $_component = 'contribute';
+
   /**
    * constructor function
+   *
+   * @param array $inputData contents of HTTP REQUEST
+   *
+   * @throws CRM_Core_Exception
    */
   function __construct($inputData) {
     $this->setInputParameters($inputData);
index e1384e586cd7113f6b440c9f2a21518f944cb14a..d0e7be6a3f749166163c434a6b713632902d418e 100644 (file)
@@ -38,5 +38,14 @@ $config = CRM_Core_Config::singleton();
 $log = new CRM_Utils_SystemLogger();
 $log->alert('payment_notification processor_name=AuthNet', $_REQUEST);
 
-$authorizeNetIPN = new CRM_Core_Payment_AuthorizeNetIPN();
-$authorizeNetIPN->main();
+$authorizeNetIPN = new CRM_Core_Payment_AuthorizeNetIPN($_REQUEST);
+try{
+  $authorizeNetIPN->main();
+}
+catch(CRM_Core_Exception $e) {
+  CRM_Core_Error::debug_log_message($e->getMessage());
+  CRM_Core_Error::debug_var('error data', $e->getErrorData(), TRUE, TRUE);
+  CRM_Core_Error::debug_var('REQUEST', $_REQUEST, TRUE, TRUE);
+  echo "The transaction has failed. Please review the log for more detail";
+}
+
diff --git a/tests/phpunit/CRM/Core/Payment/AuthorizeNetIPNTest.php b/tests/phpunit/CRM/Core/Payment/AuthorizeNetIPNTest.php
new file mode 100644 (file)
index 0000000..8269f13
--- /dev/null
@@ -0,0 +1,129 @@
+<?php
+
+require_once 'CiviTest/CiviUnitTestCase.php';
+
+/**
+ * Class CRM_Core_Payment_PayPalProIPNTest
+ */
+class CRM_Core_Payment_AuthorizeNetIPNTest extends CiviUnitTestCase {
+  protected $_contributionID;
+  protected $_invoiceID = 'c2r9c15f7be20b4f3fef1f77e4c37424';
+  protected $_financialTypeID = 1;
+  protected $_contactID;
+  protected $_contributionRecurID;
+  protected $_contributionPageID;
+  protected $_paymentProcessorID;
+
+  /**
+   * @return array
+   */
+  function get_info() {
+    return array(
+      'name' => 'Authorize.net IPN processing',
+      'description' => 'Authorize.net IPN methods.',
+      'group' => 'Payment Processor Tests',
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+    $this->_paymentProcessorID = $this->paymentProcessorCreate(array(
+      'payment_processor_type_id' => 'AuthNet',
+    ));
+    $this->_contactID = $this->individualCreate();
+    $contributionPage = $this->callAPISuccess('contribution_page', 'create', array(
+      'title' => "Test Contribution Page",
+      'financial_type_id' => $this->_financialTypeID,
+      'currency' => 'USD',
+      'payment_processor' => $this->_paymentProcessorID,
+    ));
+    $this->_contributionPageID = $contributionPage['id'];
+  }
+
+  function tearDown() {
+    $this->quickCleanUpFinancialEntities();
+  }
+
+  /**
+   * test IPN response updates contribution_recur & contribution for first & second contribution
+   */
+  function testIPNPaymentRecurSuccess() {
+    $this->setupRecurringPaymentProcessorTransaction();
+    $paypalIPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurTransaction());
+    $paypalIPN->main();
+    $contribution = $this->callAPISuccess('contribution', 'getsingle', array('id' => $this->_contributionID));
+    $this->assertEquals(1, $contribution['contribution_status_id']);
+    $this->assertEquals('6511143069', $contribution['trxn_id']);
+    // source gets set by processor
+    $this->assertTrue(substr($contribution['contribution_source'], 0, 20) == "Online Contribution:");
+    $contributionRecur = $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $this->_contributionRecurID));
+    $this->assertEquals(5, $contributionRecur['contribution_status_id']);
+    $paypalIPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurSubsequentTransaction());
+    $paypalIPN->main();
+    $contribution = $this->callAPISuccess('contribution', 'get', array('contribution_recur_id' => $this->_contributionRecurID, 'sequential' => 1));
+    $this->assertEquals(2, $contribution['count']);
+    $this->assertEquals('second_one', $contribution['values'][1]['trxn_id']);
+  }
+
+  /**
+   *
+   */
+  function getRecurTransaction() {
+    return array(
+      "x_amount" => "200.00",
+      "x_country" => 'US',
+      "x_phone" => "",
+      "x_fax" => "",
+      "x_email" => "me@gmail.com",
+      "x_description" => "lots of money",
+      "x_type" => "auth_capture",
+      "x_ship_to_first_name" => "",
+      "x_ship_to_last_name" => "",
+      "x_ship_to_company" => "",
+      "x_ship_to_address" => "",
+      "x_ship_to_city" => "",
+      "x_ship_to_state" => "",
+      "x_ship_to_zip" => "",
+      "x_ship_to_country" => "",
+      "x_tax" => "0.00",
+      "x_duty" => "0.00",
+      "x_freight" => "0.00",
+      "x_tax_exempt" => "FALSE",
+      "x_po_num" => "",
+      "x_MD5_Hash" => "1B7C0C5B4DEDD9CAD0636E35E22FC594",
+      "x_cvv2_resp_code" => "",
+      "x_cavv_response" => "",
+      "x_test_request" => "false",
+      "x_subscription_id" => $this->_contributionRecurID,
+      "x_subscription_paynum" => "1",
+      'x_first_name' => 'Robert',
+      'x_zip' => '90210',
+      'x_state' => 'WA',
+      'x_city' => 'Dallas',
+      'x_address' => '41 My ST',
+      'x_invoice_num' => $this->_contributionID,
+      'x_cust_id' => $this->_contactID,
+      'x_company' => 'nowhere@civicrm.org',
+      'x_last_name' => 'Roberts',
+      'x_account_number' => 'XXXX5077',
+      'x_card_type' => 'Visa',
+      'x_method' => 'CC',
+      'x_trans_id' => '6511143069',
+      'x_auth_code' => '123456',
+      'x_avs_code' => 'Z',
+      'x_response_reason_text' => 'This transaction has been approved.',
+      'x_response_reason_code' => '1',
+      'x_response_code' => '1'
+    );
+  }
+
+  /**
+   * @return array
+   */
+  function getRecurSubsequentTransaction() {
+    return array_merge($this->getRecurTransaction(), array(
+      'x_trans_id' => 'second_one',
+      'x_MD5_Hash' => 'EA7A3CD65A85757827F51212CA1486A8',
+    ));
+  }
+}
index 27f88eb4fa6afee2f9d6d88d1b89c1f9b189558c..923bee14c62b3f545f6279f9db9bc31a35af8497 100644 (file)
@@ -186,7 +186,7 @@ class CRM_Core_Payment_AuthorizeNetTest extends CiviUnitTestCase {
 
     // turn verifySSL off
     CRM_Core_BAO_Setting::setItem('0', CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'verifySSL');
-    $result = $this->processor->doDirectPayment($params);
+    $this->processor->doDirectPayment($params);
     // turn verifySSL on
     CRM_Core_BAO_Setting::setItem('0', CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, 'verifySSL');
 
index b9bb9c642ec99a23f34a095a05380af3bb6802a3..1cc81efbd66dc8e005c07d1dc48bdf1f2b60ca10 100644 (file)
@@ -65,7 +65,7 @@ class CRM_Core_Payment_BaseIPNTest extends CiviUnitTestCase {
   function setUp() {
     parent::setUp();
     $this->input = $this->ids = $this->objects = array();
-    $this->IPN = new CRM_Core_Payment_AuthorizeNetIPN();
+    $this->IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->input);
 
     $this->_contactId = $this->individualCreate();
     $this->ids['contact'] = $this->_contactId;
index a8790b52b3f9345a14376c3c8a44361f5d8b035d..d6240aa6547edb7f01c5f86ef78113ac126830c1 100644 (file)
@@ -62,13 +62,6 @@ class CRM_Core_Payment_PayPalProIPNTest extends CiviUnitTestCase {
       )
     );
     $this->_contributionPageID = $contributionPage['id'];
-
-    $this->_financialTypeId = 1;
-
-    // copier & paster from A.net - so have commenter out - uncomment if requirer
-    //for some strange unknown reason, in batch more this value gets set to null
-    // so crure hack here to avoir an exception anr hence an error
-    //$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array( );
   }
 
   function tearDown() {
@@ -79,7 +72,7 @@ class CRM_Core_Payment_PayPalProIPNTest extends CiviUnitTestCase {
    * test IPN response updates contribution_recur & contribution for first & second contribution
    */
   function testIPNPaymentRecurSuccess() {
-    $this->setupPaymentProcessorTransaction();
+    $this->setupRecurringPaymentProcessorTransaction();
     $paypalIPN = new CRM_Core_Payment_PayPalProIPN($this->getPaypalProRecurTransaction());
     $paypalIPN->main();
     $contribution = $this->callAPISuccess('contribution', 'getsingle', array('id' => $this->_contributionID));
@@ -104,7 +97,7 @@ class CRM_Core_Payment_PayPalProIPNTest extends CiviUnitTestCase {
    * will help future debuggers)
    */
   function testIPNPaymentCRM13743() {
-    $this->setupPaymentProcessorTransaction();
+    $this->setupRecurringPaymentProcessorTransaction();
     $firstPaymentParams = $this->getPaypalProRecurTransaction();
     $firstPaymentParams['txn_type'] = 'recurring_payment_failed';
     $paypalIPN = new CRM_Core_Payment_PayPalProIPN($firstPaymentParams);
@@ -142,7 +135,7 @@ class CRM_Core_Payment_PayPalProIPNTest extends CiviUnitTestCase {
    * Obviously if the behaviour is fixed then the test should be updated!
    */
   function testIPNPaymentExpressNoError() {
-    $this->setupPaymentProcessorTransaction();
+    $this->setupRecurringPaymentProcessorTransaction();
     $paypalIPN = new CRM_Core_Payment_PayPalProIPN($this->getPaypalExpressTransactionIPN());
     try{
       $paypalIPN->main();
@@ -157,34 +150,9 @@ class CRM_Core_Payment_PayPalProIPNTest extends CiviUnitTestCase {
     $this->fail('The Paypal Express IPN should have caused an exception');
   }
 
-
-  function setupPaymentProcessorTransaction() {
-    $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array(
-      'contact_id' => $this->_contactID,
-      'amount' => 1000,
-      'sequential' => 1,
-      'installments' => 5,
-      'frequency_unit' => 'Month',
-      'frequency_interval' => 1,
-      'invoice_id' => $this->_invoiceID,
-      'contribution_status_id' => 2,
-        'api.contribution.create' => array(
-          'total_amount' => '200',
-          'invoice_id' => $this->_invoiceID,
-          'financial_type_id' => 1,
-          'contribution_status_id' => 'Pending',
-          'contact_id' => $this->_contactID,
-          'contribution_page_id' => $this->_contributionPageID,
-          'payment_processor_id' => $this->_paymentProcessorID,
-      )
-     ));
-    $this->_contributionRecurID = $contributionRecur['id'];
-    $this->_contributionID = $contributionRecur['values']['0']['api.contribution.create']['id'];
-  }
-
   /**
    * get PaymentExpress IPN for a single transaction
-   * @return multitype:string
+   * @return array array representing a Paypal IPN POST
    */
   function getPaypalExpressTransactionIPN() {
     return array(
@@ -232,10 +200,10 @@ class CRM_Core_Payment_PayPalProIPNTest extends CiviUnitTestCase {
   }
 
   /**
-   * Get IPN results from follow on IPN transations
-   * @return multitype:string
+   * Get IPN results from follow on IPN transactions
+   * @return array array representing a Paypal IPN POST
    */
-  function getSubsequentPaypalExpressTransation() {
+  function getSubsequentPaypalExpressTransaction() {
     return array(
       'mc_gross' => '5.00',
       'period_type' => ' Regular',
@@ -347,6 +315,5 @@ class CRM_Core_Payment_PayPalProIPNTest extends CiviUnitTestCase {
    */
   function getPaypalProRecurSubsequentTransaction() {
     return array_merge($this->getPaypalProRecurTransaction(), array('txn_id' => 'secondone'));
-    ;
   }
 }
index cd87688d6a22afdd61eadb7ea6265eff50334890..a7da0fb087f6c403237791372587e4888daf0cdb 100644 (file)
@@ -2928,6 +2928,33 @@ AND    ( TABLE_NAME LIKE 'civicrm_value_%' )
    $result = $this->callAPISuccess('payment_processor', 'create', $params);
    return $result['id'];
  }
+  /**
+   * Set up initial recurring payment allowing subsequent IPN payments
+   */
+  function setupRecurringPaymentProcessorTransaction() {
+    $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array(
+      'contact_id' => $this->_contactID,
+      'amount' => 1000,
+      'sequential' => 1,
+      'installments' => 5,
+      'frequency_unit' => 'Month',
+      'frequency_interval' => 1,
+      'invoice_id' => $this->_invoiceID,
+      'contribution_status_id' => 2,
+      'processor_id' => $this->_paymentProcessorID,
+      'api.contribution.create' => array(
+        'total_amount' => '200',
+        'invoice_id' => $this->_invoiceID,
+        'financial_type_id' => 1,
+        'contribution_status_id' => 'Pending',
+        'contact_id' => $this->_contactID,
+        'contribution_page_id' => $this->_contributionPageID,
+        'payment_processor_id' => $this->_paymentProcessorID,
+      )
+    ));
+    $this->_contributionRecurID = $contributionRecur['id'];
+    $this->_contributionID = $contributionRecur['values']['0']['api.contribution.create']['id'];
+  }
 
 
   /**