Skip to content

Commit

Permalink
Merge pull request #26616 from eileenmcnaughton/anet
Browse files Browse the repository at this point in the history
Update Recurring end_date when setting status to completed
  • Loading branch information
seamuslee001 authored Jun 23, 2023
2 parents 318a395 + a6e27f8 commit 6e34b32
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 24 deletions.
1 change: 1 addition & 0 deletions CRM/Contribute/BAO/ContributionRecur.php
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,7 @@ public static function updateOnNewPayment($recurringContributionID, $paymentStat
if (!empty($existing['installments']) && self::isComplete($recurringContributionID, $existing['installments'])) {
$params['contribution_status_id'] = 'Completed';
$params['next_sched_contribution_date'] = 'null';
$params['end_date'] = 'now';
}
else {
// Only update next sched date if it's empty or up to 48 hours away because payment processors may be managing
Expand Down
9 changes: 4 additions & 5 deletions CRM/Core/Payment/AuthorizeNetIPN.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ public function main() {
\Civi::log('authorize_net')->info($errorMessage);
return;
}
if ($this->isSuccess() && ($this->getContributionStatus() !== 'Completed')) {
ContributionRecur::update(FALSE)->addWhere('id', '=', $this->getContributionRecurID())
->setValues(['trxn_id' => $this->getRecurProcessorID()])->execute();
}
$this->recur();
}
catch (CRM_Core_Exception $e) {
Expand All @@ -78,19 +82,14 @@ public function recur() {
if ($this->isSuccess()) {
// Approved
if ($this->getContributionStatus() !== 'Completed') {
$recur->trxn_id = $recur->processor_id;
$isFirstOrLastRecurringPayment = CRM_Core_Payment::RECURRING_PAYMENT_START;
}

if (($recur->installments > 0) &&
($input['subscription_paynum'] >= $recur->installments)
) {
// this is the last payment
$recur->end_date = $now;
$isFirstOrLastRecurringPayment = CRM_Core_Payment::RECURRING_PAYMENT_END;
// This end date update should occur in ContributionRecur::updateOnNewPayment
// testIPNPaymentRecurNoReceipt has test cover.
$recur->save();
}
}

Expand Down
65 changes: 48 additions & 17 deletions tests/phpunit/CRM/Core/Payment/AuthorizeNetIPNTest.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php

use Civi\Api4\ContributionRecur;
use Civi\Payment\Exception\PaymentProcessorException;
use Civi\Api4\Contribution;

Expand All @@ -24,11 +25,11 @@ public function setUp(): void {
parent::setUp();
$this->_paymentProcessorID = $this->paymentProcessorAuthorizeNetCreate(['is_test' => 0]);
$this->_contactID = $this->individualCreate();
$contributionPage = $this->callAPISuccess('contribution_page', 'create', [
$contributionPage = $this->callAPISuccess('ContributionPage', 'create', [
'title' => 'Test Contribution Page',
'financial_type_id' => $this->_financialTypeID,
'financial_type_id' => 'Donation',
'currency' => 'USD',
'payment_processor' => $this->_paymentProcessorID,
'payment_processor' => $this->ids['PaymentProcessor']['authorize_net'],
'max_amount' => 1000,
'receipt_from_email' => '[email protected]',
'receipt_from_name' => 'Pachamama',
Expand All @@ -54,7 +55,7 @@ public function testIPNPaymentRecurNoReceipt(): void {
$mut = new CiviMailUtils($this, TRUE);
// Turn off receipts in contribution page.
$api_params = [
'id' => $this->_contributionPageID,
'id' => $this->ids['ContributionPage'][0],
'is_email_receipt' => FALSE,
];
$this->callAPISuccess('ContributionPage', 'update', $api_params);
Expand All @@ -68,12 +69,13 @@ public function testIPNPaymentRecurNoReceipt(): void {
// is_email_receipt is not set to 1 if the originating contribution page
// has is_email_receipt set to 0.
$_REQUEST['mode'] = 'live';
/* @var \CRM_Contribute_Form_Contribution $form */
$form = $this->getFormObject('CRM_Contribute_Form_Contribution', [
'total_amount' => 200,
'financial_type_id' => 1,
'receive_date' => date('m/d/Y'),
'receive_date_time' => date('H:i:s'),
'contact_id' => $this->_contactID,
'contact_id' => $this->ids['Contact']['individual_0'],
'contribution_status_id' => 1,
'credit_card_number' => 4444333322221111,
'cvv2' => 123,
Expand All @@ -95,10 +97,10 @@ public function testIPNPaymentRecurNoReceipt(): void {
'installments' => 2,
'hidden_AdditionalDetail' => 1,
'hidden_Premium' => 1,
'payment_processor_id' => $this->_paymentProcessorID,
'payment_processor_id' => $this->ids['PaymentProcessor']['authorize_net'],
'currency' => 'USD',
'source' => 'bob sled race',
'contribution_page_id' => $this->_contributionPageID,
'contribution_page_id' => $this->ids['ContributionPage'][0],
'is_recur' => TRUE,
]);
$form->buildForm();
Expand Down Expand Up @@ -151,20 +153,25 @@ public function testIPNPaymentRecurNoReceipt(): void {
*/
public function testIPNPaymentRecurSuccess(): void {
CRM_Core_BAO_ConfigSetting::enableComponent('CiviCampaign');
$this->setupRecurringPaymentProcessorTransaction();
$this->setupRecurringPaymentProcessorTransaction([
'installments' => 3,
]);
$this->assertRecurStatus('Pending');

$IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurTransaction());
$IPN->main();
$contribution = $this->callAPISuccess('contribution', 'getsingle', ['id' => $this->_contributionID]);
$this->assertRecurStatus('In Progress');
$contribution = $this->callAPISuccess('Contribution', 'getsingle', ['id' => $this->ids['Contribution']['default']]);
$this->assertEquals(1, $contribution['contribution_status_id']);
$this->assertEquals('6511143069', $contribution['trxn_id']);
// source gets set by processor
$this->assertSame(strpos($contribution['contribution_source'], 'Online Contribution:'), 0);
$contributionRecur = $this->callAPISuccess('contribution_recur', 'getsingle', ['id' => $this->_contributionRecurID]);
$this->assertEquals(5, $contributionRecur['contribution_status_id']);

$IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurSubsequentTransaction());
$IPN->main();
$contribution = $this->callAPISuccess('contribution', 'get', [
'contribution_recur_id' => $this->_contributionRecurID,
$this->assertRecurStatus('In Progress');
$contribution = $this->callAPISuccess('Contribution', 'get', [
'contribution_recur_id' => $this->ids['ContributionRecur']['default'],
'sequential' => 1,
])['values'];
$this->assertCount(2, $contribution);
Expand All @@ -173,6 +180,31 @@ public function testIPNPaymentRecurSuccess(): void {
$this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($secondContribution['receive_date'])));
$this->assertEquals('expensive', $secondContribution['amount_level']);
$this->assertEquals($this->ids['campaign'][0], $secondContribution['campaign_id']);

$IPN = new CRM_Core_Payment_AuthorizeNetIPN(array_merge($this->getRecurSubsequentTransaction(), ['x_subscription_paynum' => 3, 'x_trans_id' => 'three']));
$IPN->main();
$this->assertRecurStatus('Completed');
}

/**
* Assertion for recurring status.
*
* @param string $status
*/
public function assertRecurStatus(string $status): void {
try {
$contributionRecur = ContributionRecur::get()
->addWhere('id', '=', $this->ids['ContributionRecur']['default'])
->addSelect('contribution_status_id:name', 'end_date')
->execute()->first();
$this->assertEquals($status, $contributionRecur['contribution_status_id:name']);
if ($status === 'Completed') {
$this->assertNotEmpty($contributionRecur['end_date']);
}
}
catch (CRM_Core_Exception $e) {
$this->fail('Failed to get recurring' . $e->getMessage());
}
}

/**
Expand All @@ -193,8 +225,7 @@ public function testIPNPaymentRecurSuccessMultiAuthNetProcessor(): void {
$this->assertEquals('6511143069', $contribution['trxn_id']);
// source gets set by processor
$this->assertEquals('Online Contribution:', substr($contribution['contribution_source'], 0, 20));
$contributionRecur = $this->callAPISuccess('contribution_recur', 'getsingle', ['id' => $this->_contributionRecurID]);
$this->assertEquals(5, $contributionRecur['contribution_status_id']);
$this->assertRecurStatus('In Progress');
}

/**
Expand All @@ -211,8 +242,8 @@ public function testIPNPaymentRecurSuccessSuppliedReceiveDate(): void {
$this->assertEquals('6511143069', $contribution['trxn_id']);
// source gets set by processor
$this->assertEquals('Online Contribution:', substr($contribution['contribution_source'], 0, 20));
$contributionRecur = $this->callAPISuccess('contribution_recur', 'getsingle', ['id' => $this->_contributionRecurID]);
$this->assertEquals(5, $contributionRecur['contribution_status_id']);

$this->assertRecurStatus('In Progress');
$IPN = new CRM_Core_Payment_AuthorizeNetIPN(array_merge(['receive_date' => '2010-07-01'], $this->getRecurSubsequentTransaction()));
$IPN->main();
$contribution = $this->callAPISuccess('contribution', 'get', [
Expand Down
5 changes: 3 additions & 2 deletions tests/phpunit/CiviTest/CiviUnitTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,7 @@ public function paymentProcessorAuthorizeNetCreate(array $params = []): int {
], $params);

$result = $this->callAPISuccess('PaymentProcessor', 'create', $params);
$this->ids['PaymentProcessor']['authorize_net'] = (int) $result['id'];
return (int) $result['id'];
}

Expand Down Expand Up @@ -2335,8 +2336,8 @@ public function setupRecurringPaymentProcessorTransaction(array $recurParams = [
'processor_id' => $this->ids['Contact']['individual_0'],
'api.Order.create' => $contributionParams,
], $recurParams))['values'][0];
$this->_contributionRecurID = $contributionRecur['id'];
$this->_contributionID = $contributionRecur['api.Order.create']['id'];
$this->ids['ContributionRecur']['default'] = $this->_contributionRecurID = $contributionRecur['id'];
$this->ids['Contribution']['default'] = $this->_contributionID = $contributionRecur['api.Order.create']['id'];
$this->ids['Contribution'][0] = $this->_contributionID;
}

Expand Down

0 comments on commit 6e34b32

Please sign in to comment.