From 727d9d5658d810f7d6596ec4728e195695394420 Mon Sep 17 00:00:00 2001 From: Eileen McNaughton Date: Fri, 6 Aug 2021 11:08:19 +1200 Subject: [PATCH] Reconcile remaining fields between scheduled reminders and legacy tokens This adds the last fields that were in legacy tokens but not scheduled reminders and now the same code is deriving the list for each. I wound up UI testing rather than unit testing that custom fields are still advertised without this line as the test uses rollback & adding custom fields would break that. --- CRM/Campaign/BAO/Campaign.php | 16 +++------- CRM/Contribute/Tokens.php | 9 +++++- CRM/Core/EntityTokens.php | 28 +++++++++++++++++ CRM/Core/SelectValues.php | 9 +----- .../Contribute/ActionMapping/ByTypeTest.php | 31 ++++++++++++++++++- 5 files changed, 72 insertions(+), 21 deletions(-) diff --git a/CRM/Campaign/BAO/Campaign.php b/CRM/Campaign/BAO/Campaign.php index 9c1a0447c109..a72c7d3571ce 100644 --- a/CRM/Campaign/BAO/Campaign.php +++ b/CRM/Campaign/BAO/Campaign.php @@ -301,20 +301,14 @@ public static function getPermissionedCampaigns( /** * Is CiviCampaign enabled. + * * @return bool */ - public static function isCampaignEnable() { - static $isEnable = NULL; - - if (!isset($isEnable)) { - $isEnable = FALSE; - $config = CRM_Core_Config::singleton(); - if (in_array('CiviCampaign', $config->enableComponents)) { - $isEnable = TRUE; - } + public static function isCampaignEnable(): bool { + if (!isset(Civi::$statics[__CLASS__]['is_enabled'])) { + Civi::$statics[__CLASS__]['is_enabled'] = in_array('CiviCampaign', CRM_Core_Config::singleton()->enableComponents, TRUE); } - - return $isEnable; + return Civi::$statics[__CLASS__]['is_enabled']; } /** diff --git a/CRM/Contribute/Tokens.php b/CRM/Contribute/Tokens.php index 0cdfc560fc02..d9a0030b49a7 100644 --- a/CRM/Contribute/Tokens.php +++ b/CRM/Contribute/Tokens.php @@ -67,7 +67,7 @@ protected function getApiEntityName(): string { * @return array */ protected function getExposedFields(): array { - return [ + $fields = [ 'contribution_page_id', 'source', 'id', @@ -86,7 +86,14 @@ protected function getExposedFields(): array { 'contribution_status_id', 'financial_type_id', 'payment_instrument_id', + 'cancel_reason', + 'amount_level', + 'check_number', ]; + if (CRM_Campaign_BAO_Campaign::isCampaignEnable()) { + $fields[] = 'campaign_id'; + } + return $fields; } /** diff --git a/CRM/Core/EntityTokens.php b/CRM/Core/EntityTokens.php index bf677ad1f280..2c7857217d1e 100644 --- a/CRM/Core/EntityTokens.php +++ b/CRM/Core/EntityTokens.php @@ -10,6 +10,7 @@ +--------------------------------------------------------------------+ */ +use Civi\Api4\Campaign; use Civi\Token\AbstractTokenSubscriber; use Civi\Token\TokenRow; @@ -33,6 +34,15 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber { public function evaluateToken(TokenRow $row, $entity, $field, $prefetch = NULL) { } + /** + * Loaded campaigns. + * + * As campaigns are not a true pseudoconstant we stash them here as we load them. + * + * @var array + */ + protected $campaigns; + /** * Get the entity name for api v4 calls. * @@ -167,6 +177,14 @@ public function isAddPseudoTokens($fieldName): bool { // from the metadata as yet. return FALSE; } + if ($fieldName === 'campaign_id') { + // Ah campaign_id - let me count the ways you drive me crazy. + // campaign_id is the pseudo-constant that isn't. Unnecessarily loading + // all campaigns can be a huge performance drag. + // Hence it is not defined in the metadata as a pseudoconstant. + // but we still want it to be usable like one. We brute force it... + return TRUE; + } return (bool) $this->getFieldMetadata()[$fieldName]['options']; } @@ -180,9 +198,19 @@ public function isAddPseudoTokens($fieldName): bool { * @return string * Eg. 'Completed' in the example above. * + * @throws \API_Exception * @internal function will likely be protected soon. */ public function getPseudoValue(string $realField, string $pseudoKey, $fieldValue): string { + if ($realField === 'campaign_id') { + if (!isset($this->campaigns[$fieldValue])) { + $campaign = Campaign::get(FALSE)->addWhere('id', '=', (int) $fieldValue) + ->addSelect('name', 'title')->execute()->first(); + $this->campaigns[$fieldValue]['name'] = (string) $campaign['name']; + $this->campaigns[$fieldValue]['label'] = (string) $campaign['title']; + } + return $this->campaigns[$fieldValue][$pseudoKey]; + } if ($pseudoKey === 'name') { $fieldValue = (string) CRM_Core_PseudoConstant::getName($this->getBAOName(), $realField, $fieldValue); } diff --git a/CRM/Core/SelectValues.php b/CRM/Core/SelectValues.php index 94e6da9cdc01..ca20c9d27189 100644 --- a/CRM/Core/SelectValues.php +++ b/CRM/Core/SelectValues.php @@ -568,14 +568,7 @@ public static function contributionTokens(): array { foreach ($processor->getAllTokens() as $token => $title) { $tokens['{contribution.' . $token . '}'] = $title; } - return array_merge($tokens, [ - '{contribution.cancel_reason}' => ts('Contribution Cancel Reason'), - '{contribution.amount_level}' => ts('Amount Level'), - '{contribution.check_number}' => ts('Check Number'), - '{contribution.campaign}' => ts('Contribution Campaign'), - // @todo - we shouldn't need to include custom fields here - - // remove, with test. - ], CRM_Utils_Token::getCustomFieldTokens('Contribution', TRUE)); + return $tokens; } /** diff --git a/tests/phpunit/CRM/Contribute/ActionMapping/ByTypeTest.php b/tests/phpunit/CRM/Contribute/ActionMapping/ByTypeTest.php index aa0dca703066..d10f687bd719 100644 --- a/tests/phpunit/CRM/Contribute/ActionMapping/ByTypeTest.php +++ b/tests/phpunit/CRM/Contribute/ActionMapping/ByTypeTest.php @@ -9,6 +9,8 @@ +--------------------------------------------------------------------+ */ +use Civi\Api4\Contribution; + /** * Class CRM_Contribute_ActionMapping_ByTypeTest * @group ActionSchedule @@ -151,6 +153,8 @@ public function createTestCases() { * Create a contribution record for Alice with type "Member Dues". */ public function addAliceDues(): void { + $this->enableCiviCampaign(); + $campaignID = $this->campaignCreate(); $this->ids['Contribution']['alice'] = $this->callAPISuccess('Contribution', 'create', [ 'contact_id' => $this->contacts['alice']['id'], 'receive_date' => date('Ymd', strtotime($this->targetDate)), @@ -164,6 +168,7 @@ public function addAliceDues(): void { // Having a cancel date is a bit artificial here but we can test it.... 'cancel_date' => '2021-08-09', 'contribution_status_id' => 1, + 'campaign_id' => $campaignID, 'soft_credit' => [ '1' => [ 'contact_id' => $this->contacts['carol']['id'], @@ -281,7 +286,10 @@ public function testTokenRendering(): void { non_deductible_amount = {contribution.non_deductible_amount} total_amount = {contribution.total_amount} net_amount = {contribution.net_amount} - fee_amount = {contribution.fee_amount}'; + fee_amount = {contribution.fee_amount} + campaign_id = {contribution.campaign_id} + campaign name = {contribution.campaign_id:name} + campaign label = {contribution.campaign_id:label}'; $this->schedule->save(); $this->callAPISuccess('job', 'send_reminder', []); @@ -305,6 +313,9 @@ public function testTokenRendering(): void { 'total_amount = € 100.00', 'net_amount = € 95.00', 'fee_amount = € 5.00', + 'campaign_id = 1', + 'campaign name = big_campaign', + 'campaign label = Campaign', ]; $this->mut->checkMailLog($expected); @@ -337,6 +348,9 @@ public function testTokenRendering(): void { 'total_amount = € 100.00', 'net_amount = € 95.00', 'fee_amount = € 5.00', + 'campaign_id = 1', + 'campaign name = big_campaign', + 'campaign label = Campaign', ]; foreach ($expected as $string) { $this->assertStringContainsString($string, $contributionDetails[$this->contacts['alice']['id']]['html']); @@ -354,6 +368,21 @@ public function testTokenRendering(): void { 'contribution_status_id:label', ]; $processor = new CRM_Contribute_Tokens(); + $legacyTokens = []; + $realLegacyTokens = []; + foreach (CRM_Core_SelectValues::contributionTokens() as $token => $label) { + $legacyTokens[substr($token, 14, -1)] = $label; + if (strpos($token, ':') === FALSE) { + $realLegacyTokens[substr($token, 14, -1)] = $label; + } + } + $fields = (array) Contribution::getFields()->addSelect('name', 'title')->execute()->indexBy('name'); + $allFields = []; + foreach ($fields as $field) { + $allFields[$field['name']] = $field['title']; + } + // $this->assertEquals($realLegacyTokens, $allFields); + $this->assertEquals($legacyTokens, $processor->tokenNames); foreach ($tokens as $token) { $this->assertEquals(CRM_Core_SelectValues::contributionTokens()['{contribution.' . $token . '}'], $processor->tokenNames[$token]); }