diff --git a/CRM/Core/Payment/AuthorizeNet.php b/CRM/Core/Payment/AuthorizeNet.php index 8a017838f829c2ca63e84f540a0d3abc783e9241..26b0edc6898dc76b2ba987be35e088f1025534eb 100644 --- a/CRM/Core/Payment/AuthorizeNet.php +++ b/CRM/Core/Payment/AuthorizeNet.php @@ -113,7 +113,9 @@ class CRM_Core_Payment_AuthorizeNet extends CRM_Core_Payment { */ public function doDirectPayment(&$params) { if (!defined('CURLOPT_SSLCERT')) { - return self::error(9001, 'Authorize.Net requires curl with SSL support'); + // Note that guzzle doesn't necessarily require CURL, although it prefers it. But we should leave this error + // here unless someone suggests it is not required since it's likely helpful. + throw new PaymentProcessorException('Authorize.Net requires curl with SSL support', 9001); } /* @@ -158,24 +160,13 @@ class CRM_Core_Payment_AuthorizeNet extends CRM_Core_Payment { return self::error(9004, 'It appears that this transaction is a duplicate. Have you already submitted the form once? If so there may have been a connection problem. Check your email for a receipt from Authorize.net. If you do not receive a receipt within 2 hours you can try your transaction again. If you continue to have problems please contact the site administrator.'); } - $submit = curl_init($this->_paymentProcessor['url_site']); - - if (!$submit) { - return self::error(9002, 'Could not initiate connection to payment gateway'); - } - - curl_setopt($submit, CURLOPT_POST, TRUE); - curl_setopt($submit, CURLOPT_RETURNTRANSFER, TRUE); - curl_setopt($submit, CURLOPT_POSTFIELDS, implode('&', $postFields)); - curl_setopt($submit, CURLOPT_SSL_VERIFYPEER, Civi::settings()->get('verifySSL')); - - $response = curl_exec($submit); - - if (!$response) { - return self::error(curl_errno($submit), curl_error($submit)); - } - - curl_close($submit); + $response = (string) $this->getGuzzleClient()->post($this->_paymentProcessor['url_site'], [ + 'body' => implode('&', $postFields), + 'curl' => [ + CURLOPT_RETURNTRANSFER => TRUE, + CURLOPT_SSL_VERIFYPEER => Civi::settings()->get('verifySSL'), + ], + ])->getBody(); $response_fields = $this->explode_csv($response); diff --git a/tests/phpunit/CRM/Core/Payment/AuthorizeNetTest.php b/tests/phpunit/CRM/Core/Payment/AuthorizeNetTest.php index 63b4c4bd2cc7dc4b18d50546b99b1ed9194baec9..8d6d21d6e1c51f3231a5a9228914db6ae6509001 100644 --- a/tests/phpunit/CRM/Core/Payment/AuthorizeNetTest.php +++ b/tests/phpunit/CRM/Core/Payment/AuthorizeNetTest.php @@ -38,6 +38,39 @@ class CRM_Core_Payment_AuthorizeNetTest extends CiviUnitTestCase { $this->quickCleanUpFinancialEntities(); } + /** + * Test doing a one-off payment. + * + * @throws \Civi\Payment\Exception\PaymentProcessorException + */ + public function testSinglePayment() { + $this->createMockHandler([$this->getExpectedSinglePaymentResponse()]); + $this->setUpClientWithHistoryContainer(); + $this->processor->setGuzzleClient($this->getGuzzleClient()); + $params = $this->getBillingParams(); + $params['amount'] = 5.24; + $this->processor->doPayment($params); + $this->assertEquals($this->getExpectedSinglePaymentRequest(), $this->getRequestBodies()[0]); + } + + /** + * Get the expected response from Authorize.net. + * + * @return string + */ + public function getExpectedSinglePaymentResponse() { + return '"1","1","1","(TESTMODE) This transaction has been approved.","000000","P","0","","","5.24","CC","auth_capture","","John","O'Connor","","","","","","","","","","","","","","","","","","","","","","","",""'; + } + + /** + * Get the expected request from Authorize.net. + * + * @return string + */ + public function getExpectedSinglePaymentRequest() { + return 'x_login=4y5BfuW7jm&x_tran_key=4cAmW927n8uLf5J8&x_email_customer=&x_first_name=John&x_last_name=O%27Connor&x_address=&x_city=&x_state=&x_zip=&x_country=&x_customer_ip=&x_email=&x_invoice_num=&x_amount=5.24&x_currency_code=&x_description=&x_cust_id=&x_relay_response=FALSE&x_delim_data=TRUE&x_delim_char=%2C&x_encap_char=%22&x_card_num=4444333322221111&x_card_code=123&x_exp_date=10%2F2022&x_test_request=TRUE'; + } + /** * Create a single post dated payment as a recurring transaction. * @@ -48,7 +81,7 @@ class CRM_Core_Payment_AuthorizeNetTest extends CiviUnitTestCase { $this->setUpClientWithHistoryContainer(); $this->processor->setGuzzleClient($this->getGuzzleClient()); $firstName = 'John'; - $lastName = 'Smith'; + $lastName = "O\'Connor"; $nameParams = ['first_name' => 'John', 'last_name' => $lastName]; $contactId = $this->individualCreate($nameParams); @@ -82,24 +115,11 @@ class CRM_Core_Payment_AuthorizeNetTest extends CiviUnitTestCase { 'contribution_status_id' => 2, ]); - $params = [ + $billingParams = $this->getBillingParams(); + + $params = array_merge($billingParams, [ 'qfKey' => '08ed21c7ca00a1f7d32fff2488596ef7_4454', 'hidden_CreditCard' => 1, - 'billing_first_name' => $firstName, - 'billing_middle_name' => '', - 'billing_last_name' => $lastName, - 'billing_street_address-5' => '8 Hobbitton Road', - 'billing_city-5' => 'The Shire', - 'billing_state_province_id-5' => 1012, - 'billing_postal_code-5' => 5010, - 'billing_country_id-5' => 1228, - 'credit_card_number' => '4444333322221111', - 'cvv2' => 123, - 'credit_card_exp_date' => [ - 'M' => 9, - 'Y' => 2025, - ], - 'credit_card_type' => 'Visa', 'is_recur' => 1, 'frequency_interval' => 1, 'frequency_unit' => 'month', @@ -147,12 +167,12 @@ class CRM_Core_Payment_AuthorizeNetTest extends CiviUnitTestCase { 'contributionType_name' => 'My precious', 'contributionType_accounting_code' => '', 'contributionPageID' => '', - 'email' => "{$firstName}.{$lastName}@example.com", + 'email' => 'john.smith@example.com', 'contactID' => $contactId, 'contributionID' => $contribution['id'], 'contributionTypeID' => $this->_financialTypeId, 'contributionRecurID' => $recur['id'], - ]; + ]); // turn verifySSL off Civi::settings()->set('verifySSL', '0'); @@ -193,7 +213,7 @@ class CRM_Core_Payment_AuthorizeNetTest extends CiviUnitTestCase { $start_date = date('Ymd', strtotime('+ 1 week')); $firstName = 'John'; - $lastName = 'Smith'; + $lastName = "O'Connor"; $nameParams = ['first_name' => $firstName, 'last_name' => $lastName]; $contactId = $this->individualCreate($nameParams); @@ -294,7 +314,7 @@ class CRM_Core_Payment_AuthorizeNetTest extends CiviUnitTestCase { 'postal_code' => 5010, 'country' => 'US', 'contributionPageID' => '', - 'email' => "{$firstName}.{$lastName}@example.com", + 'email' => 'john.smith@example.com', 'contactID' => $contactId, 'contributionID' => $contribution['id'], 'contributionRecurID' => $recur['id'], @@ -366,11 +386,11 @@ class CRM_Core_Payment_AuthorizeNetTest extends CiviUnitTestCase { </order> <customer> <id>' . $contactID . '</id> - <email>John.Smith@example.com</email> + <email>john.smith@example.com</email> </customer> <billTo> <firstName>John</firstName> - <lastName>Smith</lastName> + <lastName>O\'Connor</lastName> <address>8 Hobbiton Road</address> <city>The Shire</city> <state>IL</state> @@ -391,4 +411,31 @@ class CRM_Core_Payment_AuthorizeNetTest extends CiviUnitTestCase { return '<?xml version="1.0" encoding="utf-8"?><ARBCreateSubscriptionResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd"><refId>8d468ca1b1dd5c2b56c7</refId><messages><resultCode>Ok</resultCode><message><code>I00001</code><text>Successful.</text></message></messages><subscriptionId>6632052</subscriptionId><profile><customerProfileId>1512023280</customerProfileId><customerPaymentProfileId>1512027350</customerPaymentProfileId></profile></ARBCreateSubscriptionResponse>'; } + /** + * Get some basic billing parameters. + * + * @return array + */ + protected function getBillingParams(): array { + return [ + 'billing_first_name' => 'John', + 'billing_middle_name' => '', + 'billing_last_name' => "O'Connor", + 'billing_street_address-5' => '8 Hobbitton Road', + 'billing_city-5' => 'The Shire', + 'billing_state_province_id-5' => 1012, + 'billing_postal_code-5' => 5010, + 'billing_country_id-5' => 1228, + 'credit_card_number' => '4444333322221111', + 'cvv2' => 123, + 'credit_card_exp_date' => [ + 'M' => 9, + 'Y' => 2025, + ], + 'credit_card_type' => 'Visa', + 'year' => 2022, + 'month' => 10, + ]; + } + }