Skip to content

Commit

Permalink
Fix issues cancelling paypal express subscriptions
Browse files Browse the repository at this point in the history
  • Loading branch information
eileenmcnaughton committed May 17, 2018
1 parent 26b9115 commit 8c6c9d5
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 14 deletions.
3 changes: 1 addition & 2 deletions CRM/Core/Payment/PayPalImpl.php
Original file line number Diff line number Diff line change
Expand Up @@ -455,8 +455,7 @@ public function createRecurringPayments(&$params) {
* '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');

Expand Down
23 changes: 13 additions & 10 deletions CRM/Core/Payment/PayPalProIPN.php
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@ public function getInput(&$input, &$ids) {

/**
* 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
Expand All @@ -560,23 +561,25 @@ public function handlePaymentExpress() {
// 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
Expand All @@ -595,12 +598,12 @@ public function handlePaymentExpress() {
// 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);
}

/**
Expand Down
58 changes: 56 additions & 2 deletions tests/phpunit/CRM/Core/Payment/PayPalProIPNTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ public function getSubsequentPaypalExpressTransaction() {
'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',
Expand All @@ -297,7 +297,7 @@ public function getSubsequentPaypalExpressTransaction() {
'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',
Expand Down Expand Up @@ -371,4 +371,58 @@ public function getPaypalProRecurSubsequentTransaction() {
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',
];
}

}

0 comments on commit 8c6c9d5

Please sign in to comment.