dev/financial#6 exclude template contributions from the contact summary and add a...
[civicrm-core.git] / tests / phpunit / CRM / Contribute / BAO / ContributionRecurTest.php
index 138b5b9393e1e2b2e3011bd6e832978b68302b90..464bd3a81f2412adf1e42a604c5990d1ff1c790d 100644 (file)
@@ -9,6 +9,8 @@
  +--------------------------------------------------------------------+
  */
 
+use Civi\Api4\ContributionRecur;
+
 /**
  * Class CRM_Contribute_BAO_ContributionRecurTest
  * @group headless
@@ -17,14 +19,16 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
 
   use CRMTraits_Financial_OrderTrait;
 
+  protected $isValidateFinancialsOnPostAssert = TRUE;
+
   /**
    * Set up for test.
    *
-   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
    */
-  public function setUp() {
+  public function setUp(): void {
     parent::setUp();
-    $this->_ids['payment_processor'] = $this->paymentProcessorCreate();
+    $this->ids['payment_processor'] = $this->paymentProcessorCreate();
     $this->_params = [
       'contact_id' => $this->individualCreate(),
       'amount' => 3.00,
@@ -47,7 +51,7 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
       'failure_retry_date' => NULL,
       'auto_renew' => 0,
       'currency' => 'USD',
-      'payment_processor_id' => $this->_ids['payment_processor'],
+      'payment_processor_id' => $this->ids['payment_processor'],
       'is_email_receipt' => 1,
       'financial_type_id' => 1,
       'payment_instrument_id' => 1,
@@ -60,7 +64,7 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
    *
    * @throws \CRM_Core_Exception
    */
-  public function teardown() {
+  public function teardown():void {
     $this->quickCleanUpFinancialEntities();
   }
 
@@ -71,7 +75,7 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
    *
    * @throws \CRM_Core_Exception
    */
-  public function testFindSave() {
+  public function testFindSave(): void {
     $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', $this->_params);
     $dao = new CRM_Contribute_BAO_ContributionRecur();
     $dao->id = $contributionRecur['id'];
@@ -87,7 +91,7 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
    *
    * @throws \CRM_Core_Exception
    */
-  public function testCancelRecur() {
+  public function testCancelRecur(): void {
     $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', $this->_params);
     CRM_Contribute_BAO_ContributionRecur::cancelRecurContribution(['id' => $contributionRecur['id']]);
   }
@@ -95,9 +99,9 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
   /**
    * Test checking if contribution recur object can allow for changes to financial types.
    *
-   * @throws \CRM_Core_Exception
+   * @throws \CRM_Core_Exception|\CiviCRM_API3_Exception
    */
-  public function testSupportFinancialTypeChange() {
+  public function testSupportFinancialTypeChange(): void {
     $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', $this->_params);
     $this->callAPISuccess('Contribution', 'create', [
       'contribution_recur_id' => $contributionRecur['id'],
@@ -117,7 +121,7 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
    *
    * @throws \CRM_Core_Exception
    */
-  public function testUpdateRecur() {
+  public function testUpdateRecur(): void {
     $createParams = $this->_params;
     $createParams['currency'] = 'XAU';
     $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', $createParams);
@@ -140,7 +144,7 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
    * @throws \CiviCRM_API3_Exception
    * @throws \Civi\API\Exception\UnauthorizedException
    */
-  public function testGetTemplateContributionMatchTest1() {
+  public function testGetTemplateContributionMatchTest1(): void {
     $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', $this->_params);
     // Create a first contrib
     $firstContrib = $this->callAPISuccess('Contribution', 'create', [
@@ -177,7 +181,7 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
    * @throws \CiviCRM_API3_Exception
    * @throws \Civi\API\Exception\UnauthorizedException
    */
-  public function testGetTemplateContributionMatchTest() {
+  public function testGetTemplateContributionMatchTest(): void {
     $params = $this->_params;
     $params['is_test'] = 1;
     $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', $params);
@@ -211,14 +215,95 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
   }
 
   /**
-   * Test that is_template contribution is used where available
+   * Check whether template contribution is created based on the first contribution.
+   *
+   * There are three contributions created. Each of them with a different value at a custom field.
+   * The first contribution created should be copied as a template contribution.
+   * The other two should not be used as a template.
+   *
+   * Then we delete the template contribution and make sure a new one exists.
+   * At that time the second contribution should be used a template as that is the most recent one (according to the date).
    *
    * @throws \API_Exception
    * @throws \CRM_Core_Exception
    * @throws \CiviCRM_API3_Exception
    * @throws \Civi\API\Exception\UnauthorizedException
    */
-  public function testGetTemplateContributionNewTemplate() {
+  public function testCreateTemplateContributionFromFirstContributionTest(): void {
+    $custom_group = $this->customGroupCreate(['extends' => 'Contribution', 'name' => 'template']);
+    $custom_field = $this->customFieldCreate(['custom_group_id' => $custom_group['id'], 'name' => 'field']);
+
+    $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', $this->_params);
+    // Create a first test contrib
+    $date = new DateTime();
+    $firstContrib = $this->callAPISuccess('Contribution', 'create', [
+      'contribution_recur_id' => $contributionRecur['id'],
+      'total_amount' => '3.00',
+      'financial_type_id' => 1,
+      'payment_instrument_id' => 1,
+      'currency' => 'USD',
+      'contact_id' => $this->_params['contact_id'],
+      'contribution_status_id' => 1,
+      'receive_date' => $date->format('YmdHis'),
+      'custom_' . $custom_field['id'] => 'First Contribution',
+    ]);
+    $date->modify('+2 days');
+    $secondContrib = $this->callAPISuccess('Contribution', 'create', [
+      'contribution_recur_id' => $contributionRecur['id'],
+      'total_amount' => '3.00',
+      'financial_type_id' => 1,
+      'payment_instrument_id' => 1,
+      'currency' => 'USD',
+      'contact_id' => $this->_params['contact_id'],
+      'contribution_status_id' => 1,
+      'receive_date' => $date->format('YmdHis'),
+      'custom_' . $custom_field['id'] => 'Second and most recent Contribution',
+    ]);
+
+    $date->modify('-1 week');
+    $thirdContrib = $this->callAPISuccess('Contribution', 'create', [
+      'contribution_recur_id' => $contributionRecur['id'],
+      'total_amount' => '3.00',
+      'financial_type_id' => 1,
+      'payment_instrument_id' => 1,
+      'currency' => 'USD',
+      'contact_id' => $this->_params['contact_id'],
+      'contribution_status_id' => 1,
+      'receive_date' => $date->format('YmdHis'),
+      'custom_' . $custom_field['id'] => 'Third Contribution',
+    ]);
+
+    // Make sure a template contribution exists.
+    $templateContributionId = CRM_Contribute_BAO_ContributionRecur::ensureTemplateContributionExists($contributionRecur['id']);
+    $fetchedTemplate = CRM_Contribute_BAO_ContributionRecur::getTemplateContribution($contributionRecur['id']);
+    $templateContribution = \Civi\Api4\Contribution::get(FALSE)
+      ->addSelect('*', 'custom.*')
+      ->addWhere('contribution_recur_id', '=', $contributionRecur['id'])
+      ->addWhere('is_template', '=', 1)
+      ->addWhere('is_test', '=', 0)
+      ->addOrderBy('id', 'DESC')
+      ->execute();
+
+    $this->assertNotEquals($firstContrib['id'], $fetchedTemplate['id']);
+    $this->assertNotEquals($secondContrib['id'], $fetchedTemplate['id']);
+    $this->assertNotEquals($thirdContrib['id'], $fetchedTemplate['id']);
+    $this->assertEquals($templateContributionId, $fetchedTemplate['id']);
+    $this->assertTrue($fetchedTemplate['is_template']);
+    $this->assertFalse($fetchedTemplate['is_test']);
+    $this->assertEquals(1, $templateContribution->count());
+    $templateContribution = $templateContribution->first();
+    $this->assertNotNull($templateContribution['template.field']);
+    $this->assertEquals('Second and most recent Contribution', $templateContribution['template.field']);
+  }
+
+  /**
+   * Test that is_template contribution is used where available
+   *
+   * @throws \API_Exception
+   * @throws \CiviCRM_API3_Exception
+   * @throws \Civi\API\Exception\UnauthorizedException
+   */
+  public function testGetTemplateContributionNewTemplate(): void {
     $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', $this->_params);
     // Create the template
     $templateContrib = $this->callAPISuccess('Contribution', 'create', [
@@ -260,9 +345,9 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
   /**
    * Test to check if correct membership is auto renewed.
    *
-   * @throws \CRM_Core_Exception
+   * @throws \CRM_Core_Exception|\CiviCRM_API3_Exception
    */
-  public function testAutoRenewalWhenOneMemberIsDeceased() {
+  public function testAutoRenewalWhenOneMemberIsDeceased(): void {
     $contactId1 = $this->individualCreate();
     $contactId2 = $this->individualCreate();
     $membershipOrganizationId = $this->organizationCreate();
@@ -277,7 +362,7 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
     ]);
 
     // create membership type
-    $membershipTypeId1 = $this->callAPISuccess('MembershipType', 'create', [
+    $membershipTypeId1 = (int) $this->callAPISuccess('MembershipType', 'create', [
       'domain_id' => 1,
       'member_of_contact_id' => $membershipOrganizationId,
       'financial_type_id' => 'Member Dues',
@@ -288,7 +373,7 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
       'name' => 'Parent',
     ])['id'];
 
-    $membershipTypeID = $this->callAPISuccess('MembershipType', 'create', [
+    $membershipTypeID = (int) $this->callAPISuccess('MembershipType', 'create', [
       'domain_id' => 1,
       'member_of_contact_id' => $membershipOrganizationId,
       'financial_type_id' => 'Member Dues',
@@ -320,7 +405,7 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
 
     foreach ($priceFields as $priceField) {
       $lineItems = [];
-      $contactId = array_search($priceField['membership_type_id'], $contactIDs);
+      $contactId = array_search((int) $priceField['membership_type_id'], $contactIDs, TRUE);
       $lineItems[1] = [
         'price_field_id' => $priceField['priceFieldID'],
         'price_field_value_id' => $priceField['priceFieldValueID'],
@@ -405,34 +490,20 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
       'is_deceased' => 1,
     ]);
 
-    // We delete latest membership payment and line item.
-    $lineItemId = $this->callAPISuccessGetValue('LineItem', [
-      'contribution_id' => $contribution['id'],
-      'entity_id' => $membershipId2,
-      'entity_table' => 'civicrm_membership',
-      'return' => 'id',
-    ]);
-
-    // No api to delete membership payment.
-    CRM_Core_DAO::executeQuery('
-      DELETE FROM civicrm_membership_payment
-      WHERE contribution_id = %1
-        AND membership_id = %2
-    ', [
-      1 => [$contribution['id'], 'Integer'],
-      2 => [$membershipId2, 'Integer'],
-    ]);
-
-    $this->callAPISuccess('LineItem', 'delete', [
-      'id' => $lineItemId,
-    ]);
-
     // set membership recurring to null.
     $this->callAPISuccess('Membership', 'create', [
       'id' => $membershipId2,
       'contribution_recur_id' => NULL,
     ]);
 
+    $this->callAPISuccess('Contribution', 'delete', ['id' => $contribution['id']]);
+    unset($params['line_items'][1]);
+    $params['total_amount'] = 100;
+    $params['line_items'][0]['params']['id'] = $membershipId1;
+    $params['api.Payment.create']['total_amount'] = 100;
+
+    $order = $this->callAPISuccess('Order', 'create', $params);
+
     // check line item and membership payment count.
     $this->validateAllCounts($membershipId1, 5);
     $this->validateAllCounts($membershipId2, 4);
@@ -444,7 +515,7 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
 
     // record next subsequent payment (6th payment).
     $this->callAPISuccess('Contribution', 'repeattransaction', [
-      'original_contribution_id' => $contributionId,
+      'original_contribution_id' => $order['id'],
       'contribution_status_id' => 'Completed',
       'total_amount' => '100',
     ]);
@@ -476,13 +547,14 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
    *
    * @throws \CRM_Core_Exception
    */
-  public function validateAllCounts($membershipId, $count) {
+  public function validateAllCounts(int $membershipId, int $count): void {
     $memPayParams = [
       'membership_id' => $membershipId,
     ];
     $lineItemParams = [
       'entity_id' => $membershipId,
       'entity_table' => 'civicrm_membership',
+      'contribution_id' => ['>' => 0],
     ];
     $this->callAPISuccessGetCount('LineItem', $lineItemParams, $count);
     $this->callAPISuccessGetCount('MembershipPayment', $memPayParams, $count);
@@ -498,16 +570,16 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
    * we want Nov 31.
    *
    * @param int $offset
-   * @param int $year Optional input year to start
-   * @param int $month Optional input month to start
+   * @param int|null $year Optional input year to start
+   * @param int|null $month Optional input month to start
    *
    * @return array
    *   ['year' => int, 'month' => int]
    */
-  private function getYearAndMonthFromOffset(int $offset, int $year = NULL, int $month = NULL) {
+  private function getYearAndMonthFromOffset(int $offset, int $year = NULL, int $month = NULL): array {
     $dateInfo = [
-      'year' => $year ?? date('Y'),
-      'month' => ($month ?? date('m')) + $offset,
+      'year' => $year ?? (int) date('Y'),
+      'month' => ($month ?? (int) date('m')) + $offset,
     ];
     if ($dateInfo['month'] > 12) {
       $dateInfo['year']++;
@@ -522,19 +594,20 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
 
   /**
    * Test getYearAndMonthFromOffset
+   *
    * @dataProvider yearMonthProvider
    *
    * @param array $input
    * @param array $expected
    */
-  public function testGetYearAndMonthFromOffset($input, $expected) {
+  public function testGetYearAndMonthFromOffset(array $input, array $expected): void {
     $this->assertEquals($expected, $this->getYearAndMonthFromOffset($input[0], $input[1], $input[2]));
   }
 
   /**
    * data provider for testGetYearAndMonthFromOffset
    */
-  public function yearMonthProvider() {
+  public function yearMonthProvider(): array {
     return [
       // input = offset, year, current month
       ['input' => [4, 2020, 1], 'output' => ['year' => '2020', 'month' => '05']],
@@ -569,26 +642,27 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
    *
    * @throws \CRM_Core_Exception
    */
-  public function testContributionEmailReceipt() {
+  public function testContributionEmailReceipt(): void {
     $createParams = $this->_params;
     unset($createParams['trxn_id'], $createParams['invoice_id']);
 
     // pass null value to is_email_receipt
     $createParams['is_email_receipt'] = NULL;
-    $recurring1 = CRM_Contribute_BAO_ContributionRecur::add($createParams);
-    $recurring1Get = $this->callAPISuccess('ContributionRecur', 'getsingle', ['id' => $recurring1->id]);
+    $recurring1 = $this->callAPISuccess('ContributionRecur', 'create', $createParams);
+    $recurring1Get = $this->callAPISuccess('ContributionRecur', 'getsingle', ['id' => $recurring1['id']]);
     // default is_email_receipt column value is 1
     $this->assertEquals('1', $recurring1Get['is_email_receipt']);
 
     // pass empty value to is_email_receipt
     $createParams['is_email_receipt'] = '';
-    $recurring2 = CRM_Contribute_BAO_ContributionRecur::add($createParams);
-    $this->assertEquals('null', $recurring2->is_email_receipt);
+    $recurring2 = $this->callAPISuccess('ContributionRecur', 'create', $createParams);
+    $recurring2 = ContributionRecur::get(FALSE)->addWhere('id', '=', $recurring2['id'])->addSelect('is_email_receipt')->execute()->first();
+    $this->assertEquals(NULL, $recurring2['is_email_receipt']);
 
-    // pass 0 value to is_email_receipt
+    // Pass 0 value to is_email_receipt.
     $createParams['is_email_receipt'] = 0;
-    $recurring3 = CRM_Contribute_BAO_ContributionRecur::add($createParams);
-    $recurring3Get = $this->callAPISuccess('ContributionRecur', 'getsingle', ['id' => $recurring3->id]);
+    $recurring3 = $this->callAPISuccess('ContributionRecur', 'create', $createParams);
+    $recurring3Get = $this->callAPISuccess('ContributionRecur', 'getsingle', ['id' => $recurring3['id']]);
     $this->assertEquals('0', $recurring3Get['is_email_receipt']);
   }