From: eileen Date: Mon, 7 May 2018 04:30:51 +0000 (+1200) Subject: Fix issues cancelling paypal express subscriptions X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=6439290e871ba8e46ad91b6ffe54a02951cc41e5;p=civicrm-core.git Fix issues cancelling paypal express subscriptions --- diff --git a/CRM/Core/Payment/PayPalImpl.php b/CRM/Core/Payment/PayPalImpl.php index 642ee302ea..8ab1bbec3a 100644 --- a/CRM/Core/Payment/PayPalImpl.php +++ b/CRM/Core/Payment/PayPalImpl.php @@ -455,8 +455,7 @@ class CRM_Core_Payment_PayPalImpl extends CRM_Core_Payment { * 'ack' => 'Success', * 'version' => '56.0', * 'build' => '39949200',) - */ - + */ $params['trxn_id'] = $result['profileid']; $params['payment_status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending'); diff --git a/CRM/Core/Payment/PayPalProIPN.php b/CRM/Core/Payment/PayPalProIPN.php index d230762395..6a4fe29e29 100644 --- a/CRM/Core/Payment/PayPalProIPN.php +++ b/CRM/Core/Payment/PayPalProIPN.php @@ -542,6 +542,7 @@ INNER JOIN civicrm_membership_payment mp ON m.id = mp.membership_id AND mp.contr /** * Handle payment express IPNs. + * * For one off IPNS no actual response is required * Recurring is more difficult as we have limited confirmation material * lets look up invoice id in recur_contribution & rely on the unique transaction id to ensure no @@ -560,23 +561,25 @@ INNER JOIN civicrm_membership_payment mp ON m.id = mp.membership_id AND mp.contr // as membership id etc can be derived by the load objects fn $objects = $ids = $input = array(); $isFirst = FALSE; + $input['invoice'] = self::getValue('i', FALSE); $input['txnType'] = $this->retrieve('txn_type', 'String'); - if ($input['txnType'] != 'recurring_payment') { + $contributionRecur = civicrm_api3('contribution_recur', 'getsingle', array( + 'return' => 'contact_id, id, payment_processor_id', + 'invoice_id' => $input['invoice'], + )); + + if ($input['txnType'] !== 'recurring_payment' && $input['txnType'] !== 'recurring_payment_profile_created') { throw new CRM_Core_Exception('Paypal IPNS not handled other than recurring_payments'); } - $input['invoice'] = self::getValue('i', FALSE); + $this->getInput($input, $ids); - if ($this->transactionExists($input['trxn_id'])) { + if ($input['txnType'] === 'recurring_payment' && $this->transactionExists($input['trxn_id'])) { throw new CRM_Core_Exception('This transaction has already been processed'); } - $contributionRecur = civicrm_api3('contribution_recur', 'getsingle', array( - 'return' => 'contact_id, id', - 'invoice_id' => $input['invoice'], - )); $ids['contact'] = $contributionRecur['contact_id']; $ids['contributionRecur'] = $contributionRecur['id']; - $result = civicrm_api3('contribution', 'getsingle', array('invoice_id' => $input['invoice'])); + $result = civicrm_api3('contribution', 'getsingle', ['invoice_id' => $input['invoice'], 'contribution_test' => '']); $ids['contribution'] = $result['id']; //@todo hard - coding 'pending' for now @@ -595,12 +598,12 @@ INNER JOIN civicrm_membership_payment mp ON m.id = mp.membership_id AND mp.contr // membership would be an easy add - but not relevant to my customer... $this->_component = $input['component'] = 'contribute'; $input['trxn_date'] = date('Y-m-d-H-i-s', strtotime(self::retrieve('time_created', 'String'))); - $paymentProcessorID = self::getPayPalPaymentProcessorID(); + $paymentProcessorID = $contributionRecur['payment_processor_id']; if (!$this->validateData($input, $ids, $objects, TRUE, $paymentProcessorID)) { throw new CRM_Core_Exception('Data did not validate'); } - return $this->recur($input, $ids, $objects, $isFirst); + $this->recur($input, $ids, $objects, $isFirst); } /** diff --git a/tests/phpunit/CRM/Core/Payment/PayPalProIPNTest.php b/tests/phpunit/CRM/Core/Payment/PayPalProIPNTest.php index 5b379d2d4f..8072fc9bfb 100644 --- a/tests/phpunit/CRM/Core/Payment/PayPalProIPNTest.php +++ b/tests/phpunit/CRM/Core/Payment/PayPalProIPNTest.php @@ -285,7 +285,7 @@ class CRM_Core_Payment_PayPalProIPNTest extends CiviUnitTestCase { 'amount_per_cycle' => '5.00', 'payer_status' => 'unverified', 'currency_code' => 'USD', - 'business' => 'mpa@mainepeoplesalliance.org', + 'business' => 'mpa@example.com', 'address_country' => 'UNITED STATES', 'address_city' => 'Limestone', 'verify_sign' => 'AXi4DULbes8quzIiq2YNsdTJH5ciPPPzG9PcQvkQg4BjfvWi8aY9GgDb', @@ -297,7 +297,7 @@ class CRM_Core_Payment_PayPalProIPNTest extends CiviUnitTestCase { 'payment_type' => 'instant', 'last_name' => 'Morrissette', 'address_state' => 'ME', - 'receiver_email' => 'info@civicrm.org', + 'receiver_email' => 'info@example.com', 'payment_fee' => '0.41', 'receiver_id' => 'GTH8P7UQWWTY6', 'txn_type' => 'recurring_payment', @@ -371,4 +371,58 @@ class CRM_Core_Payment_PayPalProIPNTest extends CiviUnitTestCase { return array_merge($this->getPaypalProRecurTransaction(), array('txn_id' => 'secondone')); } + /** + * Test IPN response update for a paypal express profile creation confirmation. + */ + public function testIPNPaymentExpressRecurSuccess() { + $this->setupRecurringPaymentProcessorTransaction(['processor_id' => '']); + $paypalIPN = new CRM_Core_Payment_PayPalProIPN($this->getPaypalExpressRecurSubscriptionConfirmation()); + $paypalIPN->main(); + $contributionRecur = $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $this->_contributionRecurID)); + $this->assertEquals('I-JW77S1PY2032', $contributionRecur['processor_id']); + } + + /** + * Get response consistent with creating a new profile. + * + * @return array + */ + public function getPaypalExpressRecurSubscriptionConfirmation() { + return [ + 'payment_cycle' => 'Monthly', + 'txn_type' => 'recurring_payment_profile_created', + 'last_name' => 'buyer', + 'next_payment_date' => '03:00:00 May 09, 2018 PDT', + 'residence_country' => 'GB', + 'initial_payment_amount' => '0.00', + 'rp_invoice_id' => 'i=' . $this->_invoiceID + . '&m=&c=' . $this->_contributionID + . '&r=' . $this->_contributionRecurID + . '&b=' . $this->_contactID + . '&p=' . $this->_contributionPageID, + 'currency_code' => 'GBP', + 'time_created' => '12:39:01 May 09, 2018 PDT', + 'verify_sign' => 'AUg223oCjn4HgJXKkrICawXQ3fyUA2gAd1.f1IPJ4r.9sln-nWcB-EJG', + 'period_type' => 'Regular', + 'payer_status' => 'verified', + 'test_ipn' => '1', + 'tax' => '0.00', + 'payer_email' => 'payer@example.com', + 'first_name' => 'test', + 'receiver_email' => 'shop@example.com', + 'payer_id' => 'BWXXXM8111HDS', + 'product_type' => 1, + 'shipping' => '0.00', + 'amount_per_cycle' => '6.00', + 'profile_status' => 'Active', + 'charset' => 'windows-1252', + 'notify_version' => '3.9', + 'amount' => '6.00', + 'outstanding_balance' => '0.00', + 'recurring_payment_id' => 'I-JW77S1PY2032', + 'product_name' => '6 Per 1 month', + 'ipn_track_id' => '6255554274055', + ]; + } + }