Add paid_amount, balance_amount, tax_exclusive_amount to apiv4
authorEileen McNaughton <emcnaughton@wikimedia.org>
Wed, 15 Jun 2022 05:33:42 +0000 (17:33 +1200)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Tue, 2 Aug 2022 05:50:06 +0000 (17:50 +1200)
CRM/Core/BAO/FinancialTrxn.php
Civi/Api4/Service/Spec/Provider/ContributionGetSpecProvider.php [new file with mode: 0644]
Civi/Schema/Traits/DataTypeSpecTrait.php
tests/phpunit/CRM/Contribute/ActionMapping/ByTypeTest.php
tests/phpunit/CRM/Core/BAO/FinancialTrxnTest.php

index 33d2083254be4895adf68f71f636c767c0dc3955..a788e7fa6c43e8e8895926cdee6935ce42eeea9f 100644 (file)
@@ -401,6 +401,8 @@ WHERE ceft.entity_id = %1";
    * @param int $contributionID
    * @param bool $includeRefund
    *
+   * @deprecated use Apiv4.
+   *
    * @return float
    */
   public static function getTotalPayments($contributionID, $includeRefund = FALSE): float {
diff --git a/Civi/Api4/Service/Spec/Provider/ContributionGetSpecProvider.php b/Civi/Api4/Service/Spec/Provider/ContributionGetSpecProvider.php
new file mode 100644 (file)
index 0000000..056dbb1
--- /dev/null
@@ -0,0 +1,113 @@
+<?php
+
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+namespace Civi\Api4\Service\Spec\Provider;
+
+use Civi\Api4\Service\Spec\FieldSpec;
+use Civi\Api4\Service\Spec\RequestSpec;
+
+class ContributionGetSpecProvider implements Generic\SpecProviderInterface {
+
+  /**
+   * @param \Civi\Api4\Service\Spec\RequestSpec $spec
+   *
+   * @throws \CRM_Core_Exception
+   */
+  public function modifySpec(RequestSpec $spec): void {
+    // Amount paid field
+    if (!$spec->getValue('paid_amount')) {
+      $field = new FieldSpec('paid_amount', 'Contribution', 'Float');
+      $field->setLabel(ts('Amount Paid'))
+        ->setTitle(ts('Amount Paid'))
+        ->setDescription(ts('Amount paid'))
+        ->setType('Extra')
+        ->setDataType('Money')
+        ->setReadonly(TRUE)
+        ->setSqlRenderer([__CLASS__, 'calculateAmountPaid']);
+      $spec->addFieldSpec($field);
+    }
+    if (!$spec->getValue('balance_amount')) {
+      $field = new FieldSpec('balance_amount', 'Contribution', 'Float');
+      $field->setLabel(ts('Balance'))
+        ->setTitle(ts('Balance'))
+        ->setDescription(ts('Balance'))
+        ->setType('Extra')
+        ->setDataType('Money')
+        ->setReadonly(TRUE)
+        ->setSqlRenderer([__CLASS__, 'calculateBalance']);
+      $spec->addFieldSpec($field);
+    }
+    if (!$spec->getValue('tax_exclusive_amount')) {
+      $field = new FieldSpec('tax_exclusive_amount', 'Contribution', 'Float');
+      $field->setLabel(ts('Tax Exclusive Amount'))
+        ->setTitle(ts('Tax Exclusive Amount'))
+        ->setDescription(ts('Tax Exclusive Amount'))
+        ->setType('Extra')
+        ->setDataType('Money')
+        ->setReadonly(TRUE)
+        ->setSqlRenderer([__CLASS__, 'calculateTaxExclusiveAmount']);
+      $spec->addFieldSpec($field);
+    }
+  }
+
+  /**
+   * @param string $entity
+   * @param string $action
+   *
+   * @return bool
+   */
+  public function applies($entity, $action): bool {
+    return $entity === 'Contribution' && $action === 'get';
+  }
+
+  /**
+   * Generate SQL for amount_paid field
+   *
+   * @return string
+   */
+  public static function calculateTaxExclusiveAmount(): string {
+    return 'COALESCE(a.total_amount, 0) - COALESCE(a.tax_amount, 0)';
+  }
+
+  /**
+   * Generate SQL for amount_paid field
+   *
+   * @return string
+   */
+  public static function calculateAmountPaid(): string {
+    $statusIDs = [
+      \CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'),
+      \CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Refunded'),
+    ];
+
+    return "COALESCE((SELECT SUM(ft.total_amount) FROM civicrm_financial_trxn ft
+      INNER JOIN civicrm_entity_financial_trxn eft ON (eft.financial_trxn_id = ft.id AND eft.entity_table = 'civicrm_contribution')
+      WHERE eft.entity_id = a.id AND ft.is_payment = 1 AND ft.status_id IN (" . implode(',', $statusIDs) . ')), 0)';
+  }
+
+  /**
+   * Generate SQL for age field
+   *
+   * @return string
+   */
+  public static function calculateBalance(): string {
+    $statusIDs = [
+      \CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'),
+      \CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Refunded'),
+    ];
+
+    return "a.total_amount - COALESCE((SELECT SUM(ft.total_amount) FROM civicrm_financial_trxn ft
+      INNER JOIN civicrm_entity_financial_trxn eft ON (eft.financial_trxn_id = ft.id AND eft.entity_table = 'civicrm_contribution')
+      WHERE eft.entity_id = a.id AND ft.is_payment = 1 AND ft.status_id IN (" . implode(',', $statusIDs) . ')), 0)';
+  }
+
+}
index 6b0a00af9a132e750c318e6d5df4cd4fac46cb84..0afbef7e269515e23f942a82ae7825dcea21c402 100644 (file)
@@ -63,7 +63,7 @@ trait DataTypeSpecTrait {
    * @param $dataType
    *
    * @return $this
-   * @throws \Exception
+   * @throws \CRM_Core_Exception
    */
   public function setDataType($dataType) {
     if (array_key_exists($dataType, self::$typeAliases)) {
@@ -71,7 +71,7 @@ trait DataTypeSpecTrait {
     }
 
     if (!in_array($dataType, $this->getValidDataTypes())) {
-      throw new \Exception(sprintf('Invalid data type "%s', $dataType));
+      throw new \CRM_Core_Exception(sprintf('Invalid data type "%s', $dataType));
     }
 
     $this->dataType = $dataType;
index 9ce73d2f0dd0f03007d5ed4e6476639bbda13bda..24fffc1d489706a692ef71362e5a64d02709db67 100644 (file)
@@ -315,6 +315,8 @@ class CRM_Contribute_ActionMapping_ByTypeTest extends \Civi\ActionSchedule\Abstr
       total_amount = {contribution.total_amount}
       net_amount = {contribution.net_amount}
       fee_amount = {contribution.fee_amount}
+      paid_amount = {contribution.paid_amount}
+      balance_amount = {contribution.balance_amount}
       campaign_id = {contribution.campaign_id}
       campaign name = {contribution.campaign_id:name}
       campaign label = {contribution.campaign_id:label}';
@@ -341,6 +343,8 @@ class CRM_Contribute_ActionMapping_ByTypeTest extends \Civi\ActionSchedule\Abstr
       'total_amount = €100.00',
       'net_amount = €95.00',
       'fee_amount = €5.00',
+      'paid_amount = €100.00',
+      'balance_amount = €0.00',
       'campaign_id = 1',
       'campaign name = big_campaign',
       'campaign label = Campaign',
index 8120f8277338069f25fa4655fc01a3217ae95066..959d063748c6d381f9025c2f8afbc6be69bccddb 100644 (file)
@@ -9,6 +9,8 @@
  +--------------------------------------------------------------------+
  */
 
+use Civi\Api4\Contribution;
+
 /**
  * Class CRM_Core_BAO_FinancialTrxnTest
  * @group headless
@@ -53,7 +55,7 @@ class CRM_Core_BAO_FinancialTrxnTest extends CiviUnitTestCase {
    *
    * @throws \CRM_Core_Exception
    */
-  public function testGetTotalPayments() {
+  public function testGetTotalPayments(): void {
     $contactId = $this->individualCreate();
 
     $params = [
@@ -81,13 +83,19 @@ class CRM_Core_BAO_FinancialTrxnTest extends CiviUnitTestCase {
     $totalPaymentAmount = CRM_Core_BAO_FinancialTrxn::getTotalPayments($contribution['id']);
     $this->assertEquals(0, $totalPaymentAmount, 'Amount not matching.');
 
+    $this->assertEquals(0, Contribution::get()->addWhere('id', '=', $contribution['id'])
+      ->addSelect('paid_amount')->execute()->first()['paid_amount']);
     $params['id'] = $contribution['id'];
     $params['contribution_status_id'] = 1;
 
     $contribution = $this->callAPISuccess('Contribution', 'create', $params);
 
     $totalPaymentAmount = CRM_Core_BAO_FinancialTrxn::getTotalPayments($contribution['id']);
+    $this->assertEquals('200.00', Contribution::get()->addWhere('id', '=', $contribution['id'])
+      ->addSelect('paid_amount')->execute()->first()['paid_amount']);
+
     $this->assertEquals('200.00', $totalPaymentAmount, 'Amount not matching.');
+
   }
 
   /**