From 15912a4decf275132d36ac7c8483805a49227e0e Mon Sep 17 00:00:00 2001 From: eileen Date: Fri, 4 Sep 2020 15:26:33 +1200 Subject: [PATCH] Convert PaypalPro to use Guzzle - step 1 - prepare to capture --- CRM/Core/Payment/PayPalImpl.php | 53 ++++++----- .../CRM/Core/Payment/PaypalProTest.php | 89 ++++++++++++++++++ .../CRM/Core/Payment/PaypalProTrait.php | 94 +++++++++++++++++++ 3 files changed, 211 insertions(+), 25 deletions(-) create mode 100644 tests/phpunit/CRM/Core/Payment/PaypalProTest.php create mode 100644 tests/phpunit/CRM/Core/Payment/PaypalProTrait.php diff --git a/CRM/Core/Payment/PayPalImpl.php b/CRM/Core/Payment/PayPalImpl.php index be3f794b11..2da74b4065 100644 --- a/CRM/Core/Payment/PayPalImpl.php +++ b/CRM/Core/Payment/PayPalImpl.php @@ -45,6 +45,25 @@ class CRM_Core_Payment_PayPalImpl extends CRM_Core_Payment { $this->_paymentProcessor = $paymentProcessor; } + /** + * @var GuzzleHttp\Client + */ + protected $guzzleClient; + + /** + * @return \GuzzleHttp\Client + */ + public function getGuzzleClient(): \GuzzleHttp\Client { + return $this->guzzleClient ?? new \GuzzleHttp\Client(); + } + + /** + * @param \GuzzleHttp\Client $guzzleClient + */ + public function setGuzzleClient(\GuzzleHttp\Client $guzzleClient) { + $this->guzzleClient = $guzzleClient; + } + /** * Helper function to check which payment processor type is being used. * @@ -996,35 +1015,19 @@ class CRM_Core_Payment_PayPalImpl extends CRM_Core_Payment { throw new PaymentProcessorException('curl functions NOT available.'); } - //setting the curl parameters. - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_VERBOSE, 0); - - //turning off the server and peer verification(TrustManager Concept). - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, Civi::settings()->get('verifySSL')); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, Civi::settings()->get('verifySSL') ? 2 : 0); - - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_POST, 1); + $response = (string) $this->getGuzzleClient()->post($url, [ + 'body' => $nvpreq, + 'curl' => [ + CURLOPT_RETURNTRANSFER => TRUE, + CURLOPT_SSL_VERIFYPEER => Civi::settings()->get('verifySSL'), + ], + ])->getBody(); - //setting the nvpreq as POST FIELD to curl - curl_setopt($ch, CURLOPT_POSTFIELDS, $nvpreq); - - //getting response from server - $response = curl_exec($ch); - - //converting NVPResponse to an Associative Array $result = self::deformat($response); - if (curl_errno($ch)) { - throw new PaymentProcessorException(ts('Network error') . ' ' . curl_error($ch) . curl_errno($ch), curl_errno($ch)); - } - curl_close($ch); - - $outcome = strtolower(CRM_Utils_Array::value('ack', $result)); + $outcome = strtolower($result['ack'] ?? ''); - if ($outcome != 'success' && $outcome != 'successwithwarning') { + if ($outcome !== 'success' && $outcome !== 'successwithwarning') { throw new PaymentProcessorException("{$result['l_shortmessage0']} {$result['l_longmessage0']}"); } diff --git a/tests/phpunit/CRM/Core/Payment/PaypalProTest.php b/tests/phpunit/CRM/Core/Payment/PaypalProTest.php new file mode 100644 index 0000000000..5a96d6e496 --- /dev/null +++ b/tests/phpunit/CRM/Core/Payment/PaypalProTest.php @@ -0,0 +1,89 @@ +createPaypalProProcessor(); + + $this->processor = Civi\Payment\System::singleton()->getById($this->ids['PaymentProcessor']['paypal_pro']); + } + + public function tearDown() { + $this->quickCleanUpFinancialEntities(); + parent::tearDown(); + } + + /** + * Test doing a one-off payment. + * + * @throws \Civi\Payment\Exception\PaymentProcessorException + * @throws \CiviCRM_API3_Exception + */ + public function testSinglePayment() { + $this->setupMockHandler(); + $params = $this->getBillingParams(); + $params['amount'] = 5.24; + $params['currency'] = 'USD'; + $params['invoiceID'] = 'xyz'; + $params['ip_address'] = '127.0.0.1'; + foreach ($params as $key => $value) { + // Paypal is super special and requires this. Leaving out of the more generic + // get billing params for now to make it more obvious. + // When/if PropertyBag supports all the params paypal needs we can convert & simplify this. + $params[str_replace('-5', '', str_replace('billing_', '', $key))] = $value; + } + $params['state_province'] = 'IL'; + $params['country'] = 'US'; + $this->processor->doPayment($params); + $this->assertEquals($this->getExpectedSinglePaymentRequests(), $this->getRequestBodies()); + } + + /** + * Get some basic billing parameters. + * + * These are what are entered by the form-filler. + * + * @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, + ]; + } + +} diff --git a/tests/phpunit/CRM/Core/Payment/PaypalProTrait.php b/tests/phpunit/CRM/Core/Payment/PaypalProTrait.php new file mode 100644 index 0000000000..c7e65b37b1 --- /dev/null +++ b/tests/phpunit/CRM/Core/Payment/PaypalProTrait.php @@ -0,0 +1,94 @@ +processor = Civi\Payment\System::singleton()->getById($id); + } + $responses = $this->isRecur ? $this->getExpectedRecurResponses() : $this->getExpectedSinglePaymentResponses(); + // Comment the next line out when trying to capture the response. + // see https://github.com/civicrm/civicrm-core/pull/18350 + //$this->createMockHandler($responses); + $this->setUpClientWithHistoryContainer(); + $this->processor->setGuzzleClient($this->getGuzzleClient()); + } + + /** + * Create an AuthorizeNet processors with a configured mock handler. + * + * @throws \CiviCRM_API3_Exception + */ + protected function createPaypalProProcessor() { + $processorID = $this->paymentProcessorCreate(['is_test' => 0]); + $this->setupMockHandler($processorID); + $this->ids['PaymentProcessor']['paypal_pro'] = $processorID; + } + +} -- 2.25.1