From ae00cbcee584b2926cff6a484e95c50a8b7d72f8 Mon Sep 17 00:00:00 2001 From: colemanw Date: Fri, 9 Jun 2023 15:43:52 -0400 Subject: [PATCH] Fix dev/core#4207 - Handle currency symbol in SK aggregates --- .../SearchDisplay/AbstractRunAction.php | 10 ++++- .../api/v4/SearchDisplay/SearchRunTest.php | 43 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php b/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php index 2c557f58db0a..73dfc4c92ead 100644 --- a/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php +++ b/ext/search_kit/Civi/Api4/Action/SearchDisplay/AbstractRunAction.php @@ -964,7 +964,7 @@ private function getCurrencyField(string $select):?string { $clause = $this->getSelectExpression($select); // Only deal with fields of type money. // TODO: In theory it might be possible to support aggregated columns but be careful about FULL_GROUP_BY errors - if (!($clause && $clause['expr']->isType('SqlField') && $clause['dataType'] === 'Money' && $clause['fields'])) { + if (!($clause && $clause['dataType'] === 'Money' && $clause['fields'])) { return NULL; } $moneyFieldAlias = array_keys($clause['fields'])[0]; @@ -973,7 +973,15 @@ private function getCurrencyField(string $select):?string { if ($moneyField['type'] === 'Custom') { return NULL; } + $prefix = substr($moneyFieldAlias, 0, strrpos($moneyFieldAlias, $moneyField['name'])); + + // If using aggregation, this will only work if grouping by currency + if ($clause['expr']->isType('SqlFunction')) { + $groupingByCurrency = array_intersect([$prefix . 'currency', 'currency'], $this->savedSearch['api_params']['groupBy'] ?? []); + return \CRM_Utils_Array::first($groupingByCurrency); + } + // If the entity has a field named 'currency', just assume that's it. if ($this->getField($prefix . 'currency')) { return $prefix . 'currency'; diff --git a/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php b/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php index 985d00024812..a0fe56eef5ec 100644 --- a/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php +++ b/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php @@ -1422,6 +1422,49 @@ public function testContributionCurrency():void { $this->assertEquals('¥500', $result[0]['columns'][0]['val']); } + public function testContributionAggregateCurrency():void { + $contributions = $this->saveTestRecords('Contribution', [ + 'records' => [ + ['total_amount' => 100, 'currency' => 'GBP'], + ['total_amount' => 200, 'currency' => 'USD'], + ['total_amount' => 500, 'currency' => 'JPY'], + ['total_amount' => 200, 'currency' => 'USD'], + ], + ]); + + $params = [ + 'checkPermissions' => FALSE, + 'return' => 'page:1', + 'savedSearch' => [ + 'api_entity' => 'Contribution', + 'api_params' => [ + 'version' => 4, + 'select' => ['SUM(total_amount) AS total', 'COUNT(id) AS count', 'currency'], + 'where' => [['id', 'IN', $contributions->column('id')]], + 'groupBy' => ['currency'], + ], + ], + 'display' => NULL, + 'sort' => [['currency', 'ASC']], + ]; + + $result = civicrm_api4('SearchDisplay', 'run', $params); + $this->assertCount(3, $result); + + // Currency should have been used to format the aggregated values + $this->assertEquals('GBP', $result[0]['data']['currency']); + $this->assertEquals('£100.00', $result[0]['columns'][0]['val']); + $this->assertEquals(1, $result[0]['columns'][1]['val']); + + $this->assertEquals('JPY', $result[1]['data']['currency']); + $this->assertEquals('¥500', $result[1]['columns'][0]['val']); + $this->assertEquals(1, $result[1]['columns'][1]['val']); + + $this->assertEquals('USD', $result[2]['data']['currency']); + $this->assertEquals('$400.00', $result[2]['columns'][0]['val']); + $this->assertEquals(2, $result[2]['columns'][1]['val']); + } + public function testSelectEquations() { $activities = $this->saveTestRecords('Activity', [ 'records' => [