diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php index 9440b936b0bb..21d40d568a5a 100644 --- a/CRM/Contribute/BAO/Contribution.php +++ b/CRM/Contribute/BAO/Contribution.php @@ -5590,13 +5590,19 @@ public static function getAnnualQuery($contactIDs) { $liWhere = " AND i.financial_type_id NOT IN (" . implode(',', array_keys($financialTypes)) . ")"; } $whereClauses = [ - 'b.contact_id IN (' . $contactIDs . ')', - 'b.contribution_status_id = ' . (int) CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'), - 'b.is_test = 0', - 'b.receive_date >= ' . $startDate, - 'b.receive_date < ' . $endDate, + 'contact_id' => 'IN (' . $contactIDs . ')', + 'contribution_status_id' => '= ' . (int) CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'), + 'is_test' => ' = 0', + 'receive_date' => ['>=' . $startDate, '< ' . $endDate], ]; - CRM_Financial_BAO_FinancialType::buildPermissionedClause($whereClauses, NULL, 'b'); + CRM_Financial_BAO_FinancialType::addACLClausesToWhereClauses($whereClauses); + + $clauses = []; + foreach ($whereClauses as $key => $clause) { + $clauses[] = 'b.' . $key . " " . implode(' AND b.' . $key, (array) $clause); + } + $whereClauseString = implode(' AND ', $clauses); + $query = " SELECT COUNT(*) as count, SUM(total_amount) as amount, @@ -5604,7 +5610,7 @@ public static function getAnnualQuery($contactIDs) { currency FROM civicrm_contribution b LEFT JOIN civicrm_line_item i ON i.contribution_id = b.id AND i.entity_table = 'civicrm_contribution' $liWhere - WHERE " . implode(' AND ', $whereClauses) . " + WHERE " . $whereClauseString . " GROUP BY currency "; return $query; diff --git a/CRM/Financial/BAO/FinancialType.php b/CRM/Financial/BAO/FinancialType.php index 246716b1afd1..1b81f316fcbe 100644 --- a/CRM/Financial/BAO/FinancialType.php +++ b/CRM/Financial/BAO/FinancialType.php @@ -345,6 +345,44 @@ public static function getAvailableMembershipTypes(&$membershipTypes = NULL, $ac return $membershipTypes; } + /** + * This function adds the Financial ACL clauses to the where clause. + * + * This is currently somewhat mocking the native hook implementation + * for the acls that are in core. If the financialaclreport extension is installed + * core acls are not applied as that would result in them being applied twice. + * + * Long term we should either consolidate the financial acls in core or use only the extension. + * Both require substantial clean up before implementing and by the time the code is clean enough to + * take the final step we should + * be able to implement by removing one half of the other of this function. + * + * @param array $whereClauses + */ + public static function addACLClausesToWhereClauses(&$whereClauses) { + $originalWhereClauses = $whereClauses; + CRM_Utils_Hook::selectWhereClause('Contribution', $whereClauses); + if ($whereClauses !== $originalWhereClauses) { + // In this case permisssions have been applied & we assume the + // financialaclreport is applying these + // https://github.com/JMAConsulting/biz.jmaconsulting.financialaclreport/blob/master/financialaclreport.php#L107 + return; + } + + if (!self::isACLFinancialTypeStatus()) { + return; + } + $types = self::getAllEnabledAvailableFinancialTypes(); + if (empty($types)) { + $whereClauses['financial_type_id'] = 'IN (0)'; + } + else { + $whereClauses['financial_type_id'] = [ + 'IN (' . implode(',', array_keys($types)) . ')' + ]; + } + } + /** * Function to build a permissioned sql where clause based on available financial types. * diff --git a/tests/phpunit/CRM/Contribute/BAO/ContributionTest.php b/tests/phpunit/CRM/Contribute/BAO/ContributionTest.php index dc5db06639fc..21ac309634ae 100644 --- a/tests/phpunit/CRM/Contribute/BAO/ContributionTest.php +++ b/tests/phpunit/CRM/Contribute/BAO/ContributionTest.php @@ -337,6 +337,32 @@ public function testAnnualQueryWithFinancialACLsDisabled() { CRM_Core_DAO::executeQuery($sql); } + /** + * Test that financial type data is not added to the annual query if acls not enabled. + */ + public function testAnnualQueryWithFinancialHook() { + $this->hookClass->setHook('civicrm_selectWhereClause', array($this, 'aclIdNoZero')); + $sql = CRM_Contribute_BAO_Contribution::getAnnualQuery([1, 2, 3]); + $this->assertContains('SUM(total_amount) as amount,', $sql); + $this->assertContains('WHERE b.contact_id IN (1,2,3)', $sql); + $this->assertContains('b.id NOT IN (0)', $sql); + $this->assertNotContains('b.financial_type_id', $sql); + CRM_Core_DAO::executeQuery($sql); + } + + /** + * Add ACL denying values LIKE '0'. + * + * @param string $entity + * @param string $clauses + */ + public function aclIdNoZero($entity, &$clauses) { + if ($entity != 'Contribution') { + return; + } + $clauses['id'] = "NOT IN (0)"; + } + /** * Display sort name during. * Update multiple contributions diff --git a/tests/phpunit/CRMTraits/Financial/FinancialACLTrait.php b/tests/phpunit/CRMTraits/Financial/FinancialACLTrait.php index f8be66ebbe4b..b3f57b62b11b 100644 --- a/tests/phpunit/CRMTraits/Financial/FinancialACLTrait.php +++ b/tests/phpunit/CRMTraits/Financial/FinancialACLTrait.php @@ -62,11 +62,14 @@ protected function disableFinancialACLs() { * @param array $aclPermissions * Array of ACL permissions in the format * [[$action, $financialType], [$action, $financialType]) + * + * @return int Contact ID */ protected function createLoggedInUserWithFinancialACL($aclPermissions = [['view', 'Donation']]) { CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM']; - $this->createLoggedInUser(); + $contactID = $this->createLoggedInUser(); $this->addFinancialAclPermissions($aclPermissions); + return $contactID; } /**