diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php index d12ced551864..6b887205544e 100644 --- a/CRM/Contribute/BAO/Contribution.php +++ b/CRM/Contribute/BAO/Contribution.php @@ -236,7 +236,8 @@ public static function add(&$params, $ids = array()) { if (self::isUpdateToRecurringContribution($params)) { CRM_Contribute_BAO_ContributionRecur::updateOnNewPayment( (!empty($params['contribution_recur_id']) ? $params['contribution_recur_id'] : $params['prevContribution']->contribution_recur_id), - $contributionStatus[$params['contribution_status_id']] + $contributionStatus[$params['contribution_status_id']], + CRM_Utils_Array::value('receive_date', $params) ); } diff --git a/CRM/Contribute/BAO/ContributionRecur.php b/CRM/Contribute/BAO/ContributionRecur.php index 7678ae43ca9d..24937e2af971 100644 --- a/CRM/Contribute/BAO/ContributionRecur.php +++ b/CRM/Contribute/BAO/ContributionRecur.php @@ -815,7 +815,10 @@ public static function getRecurringFields() { * * @throws \CiviCRM_API3_Exception */ - public static function updateOnNewPayment($recurringContributionID, $paymentStatus) { + public static function updateOnNewPayment($recurringContributionID, $paymentStatus, $effectiveDate) { + if (empty($effectiveDate)) { + $effectiveDate = date('Y-m-d'); + } if (!in_array($paymentStatus, array('Completed', 'Failed'))) { return; } @@ -849,8 +852,8 @@ public static function updateOnNewPayment($recurringContributionID, $paymentStat // Only update next sched date if it's empty or 'just now' because payment processors may be managing // the scheduled date themselves as core did not previously provide any help. if (empty($existing['next_sched_contribution_date']) || strtotime($existing['next_sched_contribution_date']) == - strtotime(date('Y-m-d'))) { - $params['next_sched_contribution_date'] = date('Y-m-d', strtotime('+' . $existing['frequency_interval'] . ' ' . $existing['frequency_unit'])); + strtotime($effectiveDate)) { + $params['next_sched_contribution_date'] = date('Y-m-d', strtotime('+' . $existing['frequency_interval'] . ' ' . $existing['frequency_unit'], strtotime($effectiveDate))); } } civicrm_api3('ContributionRecur', 'create', $params); @@ -868,7 +871,9 @@ public static function updateOnNewPayment($recurringContributionID, $paymentStat */ protected static function isComplete($recurringContributionID, $installments) { $paidInstallments = CRM_Core_DAO::singleValueQuery( - 'SELECT count(*) FROM civicrm_contribution WHERE id = %1', + 'SELECT count(*) FROM civicrm_contribution + WHERE contribution_recur_id = %1 + AND contribution_status_id = ' . CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'), array(1 => array($recurringContributionID, 'Integer')) ); if ($paidInstallments >= $installments) { diff --git a/tests/phpunit/api/v3/ContributionTest.php b/tests/phpunit/api/v3/ContributionTest.php index fe48f7e36928..ecbc73c4f29d 100644 --- a/tests/phpunit/api/v3/ContributionTest.php +++ b/tests/phpunit/api/v3/ContributionTest.php @@ -2571,12 +2571,18 @@ public function testCompleteTransactionContributionPageFromAddress() { * Test completing first transaction in a recurring series. * * The status should be set to 'in progress' and the next scheduled payment date calculated. + * + * @dataProvider getScheduledDateData + * + * @param array $dataSet + * + * @throws \Exception */ - public function testCompleteTransactionSetStatusToInProgress() { + public function testCompleteTransactionSetStatusToInProgress($dataSet) { $paymentProcessorID = $this->paymentProcessorCreate(); - $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array( + $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array_merge(array( 'contact_id' => $this->_individualId, - 'installments' => '12', + 'installments' => '2', 'frequency_interval' => '1', 'amount' => '500', 'contribution_status_id' => 'Pending', @@ -2584,21 +2590,74 @@ public function testCompleteTransactionSetStatusToInProgress() { 'currency' => 'USD', 'frequency_unit' => 'month', 'payment_processor_id' => $paymentProcessorID, - )); + ), $dataSet['data'])); $contribution = $this->callAPISuccess('contribution', 'create', array_merge( $this->_params, array( 'contribution_recur_id' => $contributionRecur['id'], 'contribution_status_id' => 'Pending', + 'receive_date' => $dataSet['receive_date'], )) ); - $this->callAPISuccess('Contribution', 'completetransaction', array('id' => $contribution)); + $this->callAPISuccess('Contribution', 'completetransaction', array( + 'id' => $contribution, + 'receive_date' => $dataSet['receive_date'], + )); $contributionRecur = $this->callAPISuccessGetSingle('ContributionRecur', array( 'id' => $contributionRecur['id'], 'return' => array('next_sched_contribution_date', 'contribution_status_id'), )); $this->assertEquals(5, $contributionRecur['contribution_status_id']); - $this->assertEquals(date('Y-m-d 00:00:00', strtotime('+1 month')), $contributionRecur['next_sched_contribution_date']); + $this->assertEquals($dataSet['expected'], $contributionRecur['next_sched_contribution_date']); + $this->callAPISuccess('Contribution', 'create', array_merge( + $this->_params, + array( + 'contribution_recur_id' => $contributionRecur['id'], + 'contribution_status_id' => 'Completed', + ) + )); + $contributionRecur = $this->callAPISuccessGetSingle('ContributionRecur', array( + 'id' => $contributionRecur['id'], + 'return' => array('contribution_status_id'), + )); + $this->assertEquals(1, $contributionRecur['contribution_status_id']); + } + + /** + * Get dates for testing. + * + * @return array + */ + public function getScheduledDateData() { + $result = array(); + $result[]['2016-08-31-1-month'] = array( + 'data' => array( + 'start_date' => '2016-08-31', + 'frequency_interval' => 1, + 'frequency_unit' => 'month', + ), + 'receive_date' => '2016-08-31', + 'expected' => '2016-10-01 00:00:00', + ); + $result[]['2012-01-01-1-month'] = array( + 'data' => array( + 'start_date' => '2012-01-01', + 'frequency_interval' => 1, + 'frequency_unit' => 'month', + ), + 'receive_date' => '2012-01-01', + 'expected' => '2012-02-01 00:00:00', + ); + $result[]['2012-01-01-1-month'] = array( + 'data' => array( + 'start_date' => '2012-01-01', + 'frequency_interval' => 1, + 'frequency_unit' => 'month', + ), + 'receive_date' => '2012-02-29', + 'expected' => '2012-03-29 00:00:00', + ); + return $result; } /**