From 0dbefed32f5628f1c0bb126e1bb55c784d23698a Mon Sep 17 00:00:00 2001 From: Eileen McNaughton Date: Mon, 13 Oct 2014 15:25:57 +1300 Subject: [PATCH] CRM-15444 bring AuthorizenetIPN into line with PaypalIPN --- CRM/Core/Payment/AuthorizeNetIPN.php | 65 +++++---- CRM/Core/Payment/PayPalProIPN.php | 5 + extern/authorizeIPN.php | 13 +- .../CRM/Core/Payment/AuthorizeNetIPNTest.php | 129 ++++++++++++++++++ .../CRM/Core/Payment/AuthorizeNetTest.php | 2 +- .../phpunit/CRM/Core/Payment/BaseIPNTest.php | 2 +- .../CRM/Core/Payment/PayPalProIPNTest.php | 47 +------ tests/phpunit/CiviTest/CiviUnitTestCase.php | 27 ++++ 8 files changed, 216 insertions(+), 74 deletions(-) create mode 100644 tests/phpunit/CRM/Core/Payment/AuthorizeNetIPNTest.php diff --git a/CRM/Core/Payment/AuthorizeNetIPN.php b/CRM/Core/Payment/AuthorizeNetIPN.php index 93c43e7fe2..5597e6e04c 100644 --- a/CRM/Core/Payment/AuthorizeNetIPN.php +++ b/CRM/Core/Payment/AuthorizeNetIPN.php @@ -33,10 +33,16 @@ * */ 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

"; - exit(); + throw new CRM_Core_Exception("Could not find an entry for $name"); } return $value; - } +} /** * @param $ids diff --git a/CRM/Core/Payment/PayPalProIPN.php b/CRM/Core/Payment/PayPalProIPN.php index 6a8674917b..d52e00e0a4 100644 --- a/CRM/Core/Payment/PayPalProIPN.php +++ b/CRM/Core/Payment/PayPalProIPN.php @@ -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); diff --git a/extern/authorizeIPN.php b/extern/authorizeIPN.php index e1384e586c..d0e7be6a3f 100644 --- a/extern/authorizeIPN.php +++ b/extern/authorizeIPN.php @@ -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 index 0000000000..8269f138b7 --- /dev/null +++ b/tests/phpunit/CRM/Core/Payment/AuthorizeNetIPNTest.php @@ -0,0 +1,129 @@ + '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', + )); + } +} diff --git a/tests/phpunit/CRM/Core/Payment/AuthorizeNetTest.php b/tests/phpunit/CRM/Core/Payment/AuthorizeNetTest.php index 27f88eb4fa..923bee14c6 100644 --- a/tests/phpunit/CRM/Core/Payment/AuthorizeNetTest.php +++ b/tests/phpunit/CRM/Core/Payment/AuthorizeNetTest.php @@ -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'); diff --git a/tests/phpunit/CRM/Core/Payment/BaseIPNTest.php b/tests/phpunit/CRM/Core/Payment/BaseIPNTest.php index b9bb9c642e..1cc81efbd6 100644 --- a/tests/phpunit/CRM/Core/Payment/BaseIPNTest.php +++ b/tests/phpunit/CRM/Core/Payment/BaseIPNTest.php @@ -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; diff --git a/tests/phpunit/CRM/Core/Payment/PayPalProIPNTest.php b/tests/phpunit/CRM/Core/Payment/PayPalProIPNTest.php index a8790b52b3..d6240aa654 100644 --- a/tests/phpunit/CRM/Core/Payment/PayPalProIPNTest.php +++ b/tests/phpunit/CRM/Core/Payment/PayPalProIPNTest.php @@ -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')); - ; } } diff --git a/tests/phpunit/CiviTest/CiviUnitTestCase.php b/tests/phpunit/CiviTest/CiviUnitTestCase.php index cd87688d6a..a7da0fb087 100644 --- a/tests/phpunit/CiviTest/CiviUnitTestCase.php +++ b/tests/phpunit/CiviTest/CiviUnitTestCase.php @@ -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']; + } /** -- 2.25.1