From 07d89c14d2e8bcc00722135453e30bb51e63453d Mon Sep 17 00:00:00 2001
From: eileen <emcnaughton@wikimedia.org>
Date: Mon, 12 Oct 2020 13:29:32 +1300
Subject: [PATCH] dev/core#2115 Move financialacl code to a hook within the
 extension

applyACLFinancialTypeStatusToFeeBlock is not doing anything that can't be done with a pre
hook.

This extends the application to one more code place but that doesn't seem like a bad thing

Test for success of filtering options by financial type
---
 CRM/Member/Form/Membership.php                |  1 -
 CRM/Price/BAO/PriceSet.php                    |  4 +-
 ext/financialacls/financialacls.php           | 24 ++++++
 .../tests/phpunit/BuildAmountHookTest.php     | 79 +++++++++++++++++++
 4 files changed, 106 insertions(+), 2 deletions(-)
 create mode 100644 ext/financialacls/tests/phpunit/BuildAmountHookTest.php

diff --git a/CRM/Member/Form/Membership.php b/CRM/Member/Form/Membership.php
index cedf8eed66a..325a6a4c15f 100644
--- a/CRM/Member/Form/Membership.php
+++ b/CRM/Member/Form/Membership.php
@@ -1128,7 +1128,6 @@ class CRM_Member_Form_Membership extends CRM_Member_Form {
 
     // BEGIN Fix for dev/core/issues/860
     // Prepare fee block and call buildAmount hook - based on CRM_Price_BAO_PriceSet::buildPriceSet().
-    CRM_Price_BAO_PriceSet::applyACLFinancialTypeStatusToFeeBlock($this->_priceSet['fields']);
     CRM_Utils_Hook::buildAmount('membership', $this, $this->_priceSet['fields']);
     // END Fix for dev/core/issues/860
 
diff --git a/CRM/Price/BAO/PriceSet.php b/CRM/Price/BAO/PriceSet.php
index e1271686138..54ab46980a3 100644
--- a/CRM/Price/BAO/PriceSet.php
+++ b/CRM/Price/BAO/PriceSet.php
@@ -880,7 +880,6 @@ WHERE  id = %1";
       $feeBlock = &$form->_priceSet['fields'];
     }
 
-    self::applyACLFinancialTypeStatusToFeeBlock($feeBlock);
     // Call the buildAmount hook.
     CRM_Utils_Hook::buildAmount($component, $form, $feeBlock);
 
@@ -941,9 +940,12 @@ WHERE  id = %1";
    * @param array $feeBlock
    *   Fee block: array of price fields.
    *
+   * @deprecated not used in civi universe as at Oct 2020.
+   *
    * @return void
    */
   public static function applyACLFinancialTypeStatusToFeeBlock(&$feeBlock) {
+    CRM_Core_Error::deprecatedFunctionWarning('enacted in financialtypeacl extension');
     if (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus()) {
       foreach ($feeBlock as $key => $value) {
         foreach ($value['options'] as $k => $options) {
diff --git a/ext/financialacls/financialacls.php b/ext/financialacls/financialacls.php
index c0edae5e58c..7c8e7e4eb46 100644
--- a/ext/financialacls/financialacls.php
+++ b/ext/financialacls/financialacls.php
@@ -190,6 +190,30 @@ function financialacls_civicrm_selectWhereClause($entity, &$clauses) {
 
 }
 
+/**
+ * Remove un.
+ *
+ * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_buildAmount
+ *
+ * @param string $component
+ * @param \CRM_Core_Form $form
+ * @param array $feeBlock
+ */
+function financialacls_civicrm_buildAmount($component, $form, &$feeBlock) {
+  if (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus()) {
+    foreach ($feeBlock as $key => $value) {
+      foreach ($value['options'] as $k => $options) {
+        if (!CRM_Core_Permission::check('add contributions of type ' . CRM_Contribute_PseudoConstant::financialType($options['financial_type_id']))) {
+          unset($feeBlock[$key]['options'][$k]);
+        }
+      }
+      if (empty($feeBlock[$key]['options'])) {
+        unset($feeBlock[$key]);
+      }
+    }
+  }
+}
+
 // --- Functions below this ship commented out. Uncomment as required. ---
 
 /**
diff --git a/ext/financialacls/tests/phpunit/BuildAmountHookTest.php b/ext/financialacls/tests/phpunit/BuildAmountHookTest.php
new file mode 100644
index 00000000000..b240ac3aee6
--- /dev/null
+++ b/ext/financialacls/tests/phpunit/BuildAmountHookTest.php
@@ -0,0 +1,79 @@
+<?php
+
+use Civi\Test\HeadlessInterface;
+use Civi\Test\HookInterface;
+use Civi\Test\TransactionalInterface;
+use Civi\Api4\PriceField;
+use Civi\Api4\PriceSet;
+use Civi\Api4\PriceFieldValue;
+
+/**
+ * Test that that financial acls are applied in the context of buildAmountHook.
+ *
+ * @group headless
+ */
+class BuildAmountHookTest extends \PHPUnit\Framework\TestCase implements HeadlessInterface, HookInterface, TransactionalInterface {
+
+  use Civi\Test\ContactTestTrait;
+  use Civi\Test\Api3TestTrait;
+
+  /**
+   * @return \Civi\Test\CiviEnvBuilder
+   * @throws \CRM_Extension_Exception_ParseException
+   */
+  public function setUpHeadless() {
+    // Civi\Test has many helpers, like install(), uninstall(), sql(), and sqlFile().
+    // See: https://docs.civicrm.org/dev/en/latest/testing/phpunit/#civitest
+    return \Civi\Test::headless()
+      ->installMe(__DIR__)
+      ->apply();
+  }
+
+  /**
+   * Test api applies permissions on line item actions (delete & get).
+   */
+  public function testBuildAmount() {
+    $priceSet = PriceSet::create()->setValues(['name' => 'test', 'title' => 'test', 'extends' => 'CiviMember'])->execute()->first();
+    PriceField::create()->setValues([
+      'financial_type_id:name' => 'Donation',
+      'name' => 'donation',
+      'label' => 'donation',
+      'price_set_id' => $priceSet['id'],
+      'html_type' => 'Select',
+    ])->addChain('field_values', PriceFieldValue::save()->setRecords([
+      ['financial_type_id:name' => 'Donation', 'name' => 'a', 'label' => 'a', 'amount' => 1],
+      ['financial_type_id:name' => 'Member Dues', 'name' => 'b', 'label' => 'b', 'amount' => 2],
+    ])->setDefaults(['price_field_id' => '$id']))->execute();
+    Civi::settings()->set('acl_financial_type', TRUE);
+    $this->setPermissions([
+      'access CiviCRM',
+      'access CiviContribute',
+      'view contributions of type Donation',
+      'delete contributions of type Donation',
+      'add contributions of type Donation',
+      'edit contributions of type Donation',
+    ]);
+    $this->createLoggedInUser();
+    $form = new CRM_Member_Form_Membership();
+    $form->controller = new CRM_Core_Controller();
+    $form->set('priceSetId', $priceSet['id']);
+    CRM_Price_BAO_PriceSet::buildPriceSet($form);
+    $priceField = reset($form->_priceSet['fields']);
+    $this->assertCount(1, $priceField['options']);
+    $this->assertEquals('a', reset($priceField['options'])['name']);
+  }
+
+  /**
+   * Set ACL permissions, overwriting any existing ones.
+   *
+   * @param array $permissions
+   *   Array of permissions e.g ['access CiviCRM','access CiviContribute'],
+   */
+  protected function setPermissions(array $permissions) {
+    CRM_Core_Config::singleton()->userPermissionClass->permissions = $permissions;
+    if (isset(\Civi::$statics['CRM_Financial_BAO_FinancialType'])) {
+      unset(\Civi::$statics['CRM_Financial_BAO_FinancialType']);
+    }
+  }
+
+}
-- 
GitLab