CRM-20392 add unit test and fix for incorrect total used in line item creation code.
authorPradeep Nayak <pradpnayak@gmail.com>
Wed, 12 Apr 2017 11:32:42 +0000 (23:32 +1200)
committereileen <emcnaughton@wikimedia.org>
Wed, 19 Apr 2017 04:52:23 +0000 (16:52 +1200)
Eileen's note - this is code done by Pradeep that I am reviewing - I am committing
and merging the portion I have reviewed so far. This fixes a bug replicable in
the test Pradeep wrote, and some minor obvious cleanups such as removing unused parameters.

I've commented out some tests to complete this portion & there is still code of Pradeeps
not yet reviewed.

CRM/Contribute/BAO/Contribution.php
CRM/Contribute/Form/AdditionalPayment.php
CRM/Price/BAO/LineItem.php
tests/phpunit/CRM/Contribute/Form/AdditionalPaymentTest.php [new file with mode: 0644]

index 6e715176d1cb88db73ed3e56f1c30fa059d2e992..16169a4fa82ad3ff65907b69af0520306f9a520d 100644 (file)
@@ -3943,8 +3943,9 @@ WHERE eft.financial_trxn_id IN ({$trxnId}, {$baseTrxnId['financialTrxnId']})
       $activityType = ($paymentType == 'refund') ? 'Refund' : 'Payment';
 
       self::addActivityForPayment($entityObj, $financialTrxn, $activityType, $component, $contributionId);
+      return $financialTrxn;
     }
-    return $financialTrxn;
+
   }
 
   /**
index 8540925c5e255756f76be3a082a8072d21e123d1..799948d995750f3c17924f5779854b5db480951b 100644 (file)
@@ -99,7 +99,6 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
       return;
     }
     $this->_fromEmails = CRM_Core_BAO_Email::getFromEmail();
-    $this->_formType = CRM_Utils_Array::value('formType', $_GET);
 
     $enitityType = NULL;
     $enitityType = 'contribution';
@@ -436,10 +435,10 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
     $params["address_name-{$this->_bltID}"] = trim($params["address_name-{$this->_bltID}"]);
     $fields["address_name-{$this->_bltID}"] = 1;
 
-    $ctype = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
-      $this->_contactId,
-      'contact_type'
-    );
+    $ctype = civicrm_api3('Contact', 'getvalue', array(
+      'return' => "contact_type",
+      'id' => $this->_contactId,
+    ));
 
     $nameFields = array('first_name', 'middle_name', 'last_name');
     foreach ($nameFields as $name) {
@@ -569,9 +568,11 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
   }
 
   /**
+   * Function to send email receipt.
+   *
    * @param array $params
    *
-   * @return mixed
+   * @return bool
    */
   public function emailReceipt(&$params) {
     // email receipt sending
@@ -647,11 +648,56 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
       $sendTemplateParams['from'] = $receiptFrom;
       $sendTemplateParams['toName'] = $this->_contributorDisplayName;
       $sendTemplateParams['toEmail'] = $this->_contributorEmail;
-      $sendTemplateParams['cc'] = CRM_Utils_Array::value('cc', $this->_fromEmails);
-      $sendTemplateParams['bcc'] = CRM_Utils_Array::value('bcc', $this->_fromEmails);
     }
     list($mailSent, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate::sendTemplate($sendTemplateParams);
     return $mailSent;
   }
 
+  /**
+   * Wrapper for unit testing the post process submit function.
+   *
+   *
+   * @param array $params
+   * @param string|null $creditCardMode
+   * @param string $enitityType
+   *
+   * @throws \CiviCRM_API3_Exception
+   */
+  public function testSubmit($params, $creditCardMode = NULL, $enitityType = 'contribute') {
+    $this->_bltID = 5;
+    if (!empty($params['contribution_id'])) {
+      $this->_contributionId = $params['contribution_id'];
+
+      $paymentInfo = CRM_Core_BAO_FinancialTrxn::getPartialPaymentWithType($this->_contributionId, $enitityType);
+      $paymentDetails = CRM_Contribute_BAO_Contribution::getPaymentInfo($this->_contributionId, $enitityType, FALSE, TRUE);
+
+      $this->_amtPaid = $paymentDetails['paid'];
+      $this->_amtTotal = $paymentDetails['total'];
+
+      if (!empty($paymentInfo['refund_due'])) {
+        $this->_refund = $paymentInfo['refund_due'];
+        $this->_paymentType = 'refund';
+      }
+      elseif (!empty($paymentInfo['amount_owed'])) {
+        $this->_owed = $paymentInfo['amount_owed'];
+        $this->_paymentType = 'owed';
+      }
+    }
+
+    if (!empty($params['contact_id'])) {
+      $this->_contactId = $params['contact_id'];
+    }
+
+    if ($creditCardMode) {
+      $this->_mode = $creditCardMode;
+    }
+
+    // Required because processCreditCard calls set method on this.
+    $_SERVER['REQUEST_METHOD'] = 'GET';
+    $this->controller = new CRM_Core_Controller();
+
+    $this->_fields = array();
+    $this->submit($params);
+  }
+
 }
index 56694bd71cf66b949962fe869760d1f85d14fe6d..e1b629c4a721d07e65dc044b5d790e7371073099 100644 (file)
@@ -555,7 +555,7 @@ WHERE li.contribution_id = %1";
 
     if (!$entityId) {
       $priceSetDetails = CRM_Price_BAO_PriceSet::getDefaultPriceSet($entityTable);
-      $totalAmount = CRM_Utils_Array::value('total_amount', $params);
+      $totalAmount = CRM_Utils_Array::value('partial_payment_total', $params, CRM_Utils_Array::value('total_amount', $params));
       $financialType = CRM_Utils_Array::value('financial_type_id', $params);
       foreach ($priceSetDetails as $values) {
         if ($entityTable == 'membership') {
diff --git a/tests/phpunit/CRM/Contribute/Form/AdditionalPaymentTest.php b/tests/phpunit/CRM/Contribute/Form/AdditionalPaymentTest.php
new file mode 100644 (file)
index 0000000..50ec1fd
--- /dev/null
@@ -0,0 +1,352 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.7                                                |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2017                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ *  Test APIv3 civicrm_contribute_* functions
+ *
+ * @package CiviCRM_APIv3
+ * @subpackage API_Contribution
+ * @group headless
+ */
+class CRM_Contribute_Form_AdditionalPaymentTest extends CiviUnitTestCase {
+
+  /**
+   * Contact ID.
+   *
+   * @var int
+   */
+  protected $_individualId;
+
+  /**
+   * Parameters to create contribution.
+   *
+   * @var array
+   */
+  protected $_params;
+
+  /**
+   * Contribution ID.
+   *
+   * @var int
+   */
+  protected $_contributionId;
+
+  /**
+   * Parameters to create payment processor.
+   *
+   * @var array
+   */
+  protected $_processorParams = array();
+
+  /**
+   * Payment instrument mapping.
+   *
+   * @var array
+   */
+  protected $paymentInstruments = array();
+
+  /**
+   * Dummy payment processor.
+   *
+   * @var CRM_Core_Payment_Dummy
+   */
+  protected $paymentProcessor;
+
+  /**
+   * Payment processor ID.
+   *
+   * @var int
+   */
+  protected $paymentProcessorID;
+
+  /**
+   * Setup function.
+   */
+  public function setUp() {
+    parent::setUp();
+    $this->createLoggedInUser();
+
+    $this->_individualId = $this->individualCreate();
+    $this->_params = array(
+      'total_amount' => 100,
+      'currency' => 'USD',
+      'contact_id' => $this->_individualId,
+      'financial_type_id' => 1,
+    );
+    $this->_processorParams = array(
+      'domain_id' => 1,
+      'name' => 'Dummy',
+      'payment_processor_type_id' => 10,
+      'financial_account_id' => 12,
+      'is_active' => 1,
+      'user_name' => '',
+      'url_site' => 'http://dummy.com',
+      'url_recur' => 'http://dummy.com',
+      'billing_mode' => 1,
+    );
+
+    $instruments = $this->callAPISuccess('contribution', 'getoptions', array('field' => 'payment_instrument_id'));
+    $this->paymentInstruments = $instruments['values'];
+
+    $this->paymentProcessor = $this->dummyProcessorCreate();
+    $processor = $this->paymentProcessor->getPaymentProcessor();
+    $this->paymentProcessorID = $processor['id'];
+  }
+
+  /**
+   * Clean up after each test.
+   */
+  public function tearDown() {
+    $this->quickCleanUpFinancialEntities();
+    parent::tearDown();
+  }
+
+  /**
+   * Test the submit function that completes the partially paid Contribution using Credit Card.
+
+  public function testAddPaymentUsingCreditCardForPartialyPaidContribution() {
+    $this->createContribution('Partially paid');
+
+    // pay additional amount by using Credit Card
+    $this->submitPayment(70, 'live');
+    $this->checkResults(array(30, 70), 2);
+  }
+   */
+
+  /**
+   * Test the submit function that completes the partially paid Contribution.
+   */
+  public function testAddPaymentForPartialyPaidContribution() {
+    $this->createContribution('Partially paid');
+
+    // pay additional amount
+    $this->submitPayment(70);
+    $this->checkResults(array(30, 70), 2);
+  }
+
+  /**
+   * Test the submit function that completes the partially paid Contribution with multiple payments.
+   */
+  public function testMultiplePaymentForPartialyPaidContribution() {
+    $this->createContribution('Partially paid');
+
+    // pay additional amount
+    $this->submitPayment(50);
+    $contribution = $this->callAPISuccessGetSingle('Contribution', array('id' => $this->_contributionId));
+    $this->assertEquals('Partially paid', $contribution['contribution_status']);
+
+    // pay additional amount
+    $this->submitPayment(20);
+    $this->checkResults(array(30, 50, 20), 3);
+  }
+  /**
+   * Test the submit function that completes the partially paid Contribution with multiple payments.
+   *
+  public function testMultiplePaymentForPartialyPaidContributionWithOneCreditCardPayment() {
+    $this->createContribution('Partially paid');
+
+    // pay additional amount
+    $this->submitPayment(50);
+    $contribution = $this->callAPISuccessGetSingle('Contribution', array('id' => $this->_contributionId));
+    $this->assertEquals('Partially paid', $contribution['contribution_status']);
+
+    // pay additional amount by using credit card
+    $this->submitPayment(20, 'live');
+    $this->checkResults(array(30, 50, 20), 3);
+  }
+
+
+  /**
+   * Test the submit function that completes the pending pay later Contribution using Credit Card.
+   *
+  public function testAddPaymentUsingCreditCardForPendingPayLaterContribution() {
+    $this->createContribution('Pending');
+
+    // pay additional amount by using Credit Card
+    $this->submitPayment(100, 'live');
+    $this->checkResults(array(100), 1);
+  }
+   */
+
+  /**
+   * Test the submit function that completes the pending pay later Contribution.
+   */
+  public function testAddPaymentForPendingPayLaterContribution() {
+    $this->createContribution('Pending');
+
+    // pay additional amount
+    $this->submitPayment(70);
+    $contribution = $this->callAPISuccessGetSingle('Contribution', array('id' => $this->_contributionId));
+    $this->assertEquals('Partially paid', $contribution['contribution_status']);
+
+    // pay additional amount
+    $this->submitPayment(30);
+    $this->checkResults(array(30, 70), 2);
+  }
+
+  /**
+   * Test the submit function that completes the pending pay later Contribution with multiple payments.
+   */
+  public function testMultiplePaymentForPendingPayLaterContribution() {
+    $this->createContribution('Pending');
+
+    // pay additional amount
+    $this->submitPayment(40);
+    $contribution = $this->callAPISuccessGetSingle('Contribution', array('id' => $this->_contributionId));
+    $this->assertEquals('Partially paid', $contribution['contribution_status']);
+
+    $this->submitPayment(20);
+    $contribution = $this->callAPISuccessGetSingle('Contribution', array('id' => $this->_contributionId));
+    $this->assertEquals('Partially paid', $contribution['contribution_status']);
+
+    $this->submitPayment(30);
+    $contribution = $this->callAPISuccessGetSingle('Contribution', array('id' => $this->_contributionId));
+    $this->assertEquals('Partially paid', $contribution['contribution_status']);
+
+    $this->submitPayment(10);
+    $this->checkResults(array(40, 20, 30, 10), 4);
+  }
+
+  /**
+   * Test the submit function that completes the pending pay later Contribution with multiple payments.
+   *
+  public function testMultiplePaymentForPendingPayLaterContributionWithOneCreditCardPayment() {
+    $this->createContribution('Pending');
+
+    // pay additional amount
+    $this->submitPayment(50);
+    $contribution = $this->callAPISuccessGetSingle('Contribution', array('id' => $this->_contributionId));
+    $this->assertEquals('Partially paid', $contribution['contribution_status']);
+
+    $this->submitPayment(20, 'live');
+    $contribution = $this->callAPISuccessGetSingle('Contribution', array('id' => $this->_contributionId));
+    $this->assertEquals('Partially paid', $contribution['contribution_status']);
+
+    $this->submitPayment(20);
+    $contribution = $this->callAPISuccessGetSingle('Contribution', array('id' => $this->_contributionId));
+    $this->assertEquals('Partially paid', $contribution['contribution_status']);
+
+    $this->submitPayment(10, 'live');
+    $this->checkResults(array(50, 20, 20, 10), 4);
+  }
+   */
+
+  /**
+   * Function to create pending pay later or partially paid conntribution.
+   *
+   * @param string $typeofContribution
+   *
+   */
+  public function createContribution($typeofContribution = 'Pending') {
+    if ($typeofContribution == 'Partially paid') {
+      $contributionParams = array_merge($this->_params, array(
+        'partial_payment_total' => 100.00,
+        'partial_amount_pay' => 30,
+        'contribution_status_id' => 1,
+      ));
+    }
+    elseif ($typeofContribution == 'Pending') {
+      $contributionParams = array_merge($this->_params, array(
+        'contribution_status_id' => 2,
+        'is_pay_later' => 1,
+      ));
+    }
+    $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams);
+    $contribution = $this->callAPISuccessGetSingle('Contribution', array('id' => $contribution['id']));
+    $this->assertNotEmpty($contribution);
+    $this->assertEquals($typeofContribution, $contribution['contribution_status']);
+    $this->_contributionId = $contribution['id'];
+  }
+
+  /**
+   * Function to submit payments for contribution.
+   *
+   * @param float $amount
+   *  Payment Amount
+   * @param string $mode
+   *  Mode of Payment
+   *
+   */
+  public function submitPayment($amount, $mode = NULL) {
+    $form = new CRM_Contribute_Form_AdditionalPayment();
+
+    $submitParams = array(
+      'contribution_id' => $this->_contributionId,
+      'contact_id' => $this->_individualId,
+      'total_amount' => $amount,
+      'currency' => 'USD',
+      'financial_type_id' => 1,
+      'receive_date' => '04/21/2015',
+      'receive_date_time' => '11:27PM',
+      'trxn_date' => '2017-04-11 13:05:11',
+    );
+    if ($mode) {
+      $submitParams += array(
+        'payment_instrument_id' => array_search('Credit card', $this->paymentInstruments),
+        'payment_processor_id' => $this->paymentProcessorID,
+        'credit_card_exp_date' => array('M' => 5, 'Y' => 2025),
+        'credit_card_number' => '411111111111111',
+        'cvv2' => 234,
+        'credit_card_type' => 'Visa',
+        'billing_city-5' => 'Vancouver',
+        'billing_state_province_id-5' => 1059,
+        'billing_postal_code-5' => 1321312,
+        'billing_country_id-5' => 1228,
+      );
+    }
+    else {
+      $submitParams += array(
+        'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
+        'check_number' => 'check-12345',
+      );
+    }
+    $form->testSubmit($submitParams, $mode);
+  }
+
+  /**
+   * Function to check result.
+   *
+   * @param array $amounts
+   *    Array of payment amount for contribution
+   * @param int $count
+   *   Number payment for contribution
+   *
+   */
+  public function checkResults($amounts, $count) {
+    $contribution = $this->callAPISuccessGetSingle('Contribution', array('id' => $this->_contributionId));
+    $this->assertNotEmpty($contribution);
+    $this->assertEquals('Completed', $contribution['contribution_status']);
+
+    $this->callAPISuccessGetCount('EntityFinancialTrxn', array(
+      'entity_table' => "civicrm_contribution",
+      'entity_id' => $this->_contributionId,
+      'financial_trxn_id.is_payment' => 1,
+      'financial_trxn_id.total_amount' => array('IN' => $amounts),
+    ), $count);
+  }
+
+}