Skip to content

Commit

Permalink
dev/core#4123 Support contribution recur tokens when accessing from a…
Browse files Browse the repository at this point in the history
… contribution or membership

Use getRelatedTokens function name instead and also fix tests

Hide some unnecessary tokens and fix tests
  • Loading branch information
seamuslee001 committed May 8, 2023
1 parent c054fb5 commit f030a44
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 1 deletion.
24 changes: 24 additions & 0 deletions CRM/Contribute/Tokens.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
+--------------------------------------------------------------------+
*/

use Civi\Api4\ContributionRecur;

/**
* Class CRM_Contribute_Tokens
*
Expand Down Expand Up @@ -46,4 +48,26 @@ public function getCurrencyFieldName() {
return ['currency'];
}

/**
* Get Related Entity tokens.
*
* @return array[]
*/
protected function getRelatedTokens(): array {
$tokens = [];
$hiddenTokens = ['modified_date', 'create_date', 'trxn_id', 'invoice_id', 'is_test', 'payment_token_id', 'payment_processor_id', 'payment_instrument_id', 'cycle_day', 'installments', 'processor_id', 'next_sched_contribution_date', 'failure_count', 'failure_retry_date', 'auto_renew', 'is_email_receipt', 'contribution_status_id'];
$contributionRecurFields = ContributionRecur::getFields(FALSE)->setLoadOptions(TRUE)->execute();
foreach ($contributionRecurFields as $contributionRecurField) {
$tokens['contribution_recur_id.' . $contributionRecurField['name']] = [
'title' => $contributionRecurField['title'],
'name' => 'contribution_recur_id.' . $contributionRecurField['name'],
'type' => 'mapped',
'options' => $contributionRecurField['options'] ?? NULL,
'data_type' => $contributionRecurField['data_type'],
'audience' => in_array($contributionRecurField['name'], $hiddenTokens) ? 'hidden' : 'user',
];
}
return $tokens;
}

}
8 changes: 8 additions & 0 deletions CRM/Core/EntityTokens.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ protected function getTokenMetadata(): array {
$cacheKey = $this->getCacheKey();
if (!Civi::cache('metadata')->has($cacheKey)) {
$tokensMetadata = $this->getBespokeTokens();
$tokensMetadata = array_merge($tokensMetadata, $this->getRelatedTokens());
foreach ($this->getFieldMetadata() as $field) {
$this->addFieldToTokenMetadata($tokensMetadata, $field, $this->getExposedFields());
}
Expand Down Expand Up @@ -275,6 +276,13 @@ protected function getBespokeTokens(): array {
return [];
}

/**
* Get related entity tokens.
*/
protected function getRelatedTokens(): array {
return [];
}

/**
* Get the value for the relevant pseudo field.
*
Expand Down
22 changes: 22 additions & 0 deletions CRM/Member/Tokens.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
+--------------------------------------------------------------------+
*/

use Civi\Api4\ContributionRecur;

/**
* Class CRM_Member_Tokens
*
Expand Down Expand Up @@ -122,4 +124,24 @@ protected function getBespokeTokens(): array {
];
}

/**
* Get related tokens related to membership e.g. recurring contribution tokens
*/
protected function getRelatedTokens(): array {
$tokens = [];
$hiddenTokens = ['modified_date', 'create_date', 'trxn_id', 'invoice_id', 'is_test', 'payment_token_id', 'payment_processor_id', 'payment_instrument_id', 'cycle_day', 'installments', 'processor_id', 'next_sched_contribution_date', 'failure_count', 'failure_retry_date', 'auto_renew', 'is_email_receipt', 'contribution_status_id'];
$contributionRecurFields = ContributionRecur::getFields(FALSE)->setLoadOptions(TRUE)->execute();
foreach ($contributionRecurFields as $contributionRecurField) {
$tokens['contribution_recur_id.' . $contributionRecurField['name']] = [
'title' => $contributionRecurField['title'],
'name' => 'contribution_recur_id.' . $contributionRecurField['name'],
'type' => 'mapped',
'options' => $contributionRecurField['options'] ?? NULL,
'data_type' => $contributionRecurField['data_type'],
'audience' => in_array($contributionRecurField['name'], $hiddenTokens) ? 'hidden' : 'user',
];
}
return $tokens;
}

}
12 changes: 12 additions & 0 deletions tests/phpunit/CRM/Contribute/ActionMapping/ByTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,18 @@ public function testTokenRendering(): void {
'paid_amount' => 'Amount Paid',
'balance_amount' => 'Balance',
'tax_exclusive_amount' => 'Tax Exclusive Amount',
'contribution_recur_id.id' => 'Recurring Contribution ID',
'contribution_recur_id.contact_id' => 'Contact ID',
'contribution_recur_id.amount' => 'Amount',
'contribution_recur_id.currency' => 'Currency',
'contribution_recur_id.frequency_unit' => 'Frequency Unit',
'contribution_recur_id.frequency_interval' => 'Interval (number of units)',
'contribution_recur_id.start_date' => 'Start Date',
'contribution_recur_id.cancel_date' => 'Cancel Date',
'contribution_recur_id.cancel_reason' => 'Cancellation Reason',
'contribution_recur_id.end_date' => 'Recurring Contribution End Date',
'contribution_recur_id.financial_type_id' => 'Financial Type ID',
'contribution_recur_id.campaign_id' => 'Campaign ID',
], $comparison);
}

Expand Down
23 changes: 22 additions & 1 deletion tests/phpunit/CRM/Utils/TokenConsistencyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ public function testMembershipTokenConsistency(): void {
$tokens = $tokenProcessor->listTokens();
// Add in custom tokens as token processor supports these.
$expectedTokens = array_merge($expectedTokens, $this->getTokensAdvertisedByTokenProcessorButNotLegacy());
$this->assertEquals(array_merge($expectedTokens, $this->getDomainTokens()), $tokens);
$this->assertEquals(array_merge($expectedTokens, $this->getDomainTokens(), $this->getRecurEntityTokens('membership')), $tokens);
$tokenProcessor->addMessage('html', $tokenString, 'text/plain');
$tokenProcessor->addRow(['membershipId' => $this->getMembershipID()]);
$tokenProcessor->evaluate();
Expand Down Expand Up @@ -957,6 +957,27 @@ protected function getEventTokens(): array {
];
}

/**
* @param string $entity
*
* @return string[]
*/
protected function getRecurEntityTokens($entity): array {
return [
'{' . $entity . '.contribution_recur_id.id}' => 'Recurring Contribution ID',
'{' . $entity . '.contribution_recur_id.contact_id}' => 'Contact ID',
'{' . $entity . '.contribution_recur_id.amount}' => 'Amount',
'{' . $entity . '.contribution_recur_id.currency}' => 'Currency',
'{' . $entity . '.contribution_recur_id.frequency_unit}' => 'Frequency Unit',
'{' . $entity . '.contribution_recur_id.frequency_interval}' => 'Interval (number of units)',
'{' . $entity . '.contribution_recur_id.start_date}' => 'Start Date',
'{' . $entity . '.contribution_recur_id.cancel_date}' => 'Cancel Date',
'{' . $entity . '.contribution_recur_id.cancel_reason}' => 'Cancellation Reason',
'{' . $entity . '.contribution_recur_id.end_date}' => 'Recurring Contribution End Date',
'{' . $entity . '.contribution_recur_id.financial_type_id}' => 'Financial Type ID',
];
}

/**
* @param array $tokens
*
Expand Down
78 changes: 78 additions & 0 deletions tests/phpunit/Civi/Token/TokenProcessorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,84 @@ protected function renderUrlMessage(int $contactID): TokenRow {
return $tokenProcessor->evaluate()->getRow(0);
}

/**
* Check that we can render contribution and contribution_recur tokens when passing a contribution ID.
* This checks Bestspoke tokens
*
* @return void
* @throws \API_Exception
* @throws \Civi\API\Exception\UnauthorizedException
*/
public function testRenderContributionRecurTokenFromContribution(): void {
$cid = $this->individualCreate();
$crid = \Civi\Api4\ContributionRecur::create(FALSE)
->addValue('contact_id', $cid)
->addValue('amount', 5)
->execute()
->first()['id'];
$coid = $this->contributionCreate(['contact_id' => $cid, 'contribution_recur_id' => $crid]);

$tokenProcessor = new TokenProcessor(\Civi::dispatcher(), [
'controller' => __CLASS__,
'schema' => ['contactId', 'contributionId'],
'smarty' => FALSE,
]);
$tokenProcessor->addMessage('text', '!!{contribution.id}{contribution.contribution_recur_id.id}{contribution.contribution_recur_id.amount}!!', 'text/plain');
$tokenProcessor->addRow()->context(['contactId' => $cid, 'contributionId' => $coid]);

$expectText = [
"!!{$coid}{$crid}$5.00!!",
];

$rowCount = 0;
foreach ($tokenProcessor->evaluate()->getRows() as $key => $row) {
/** @var TokenRow */
$this->assertTrue($row instanceof TokenRow);
$this->assertEquals($expectText[$key], $row->render('text'));
$rowCount++;
}
$this->assertEquals(1, $rowCount);
}

/**
* Check that we can render membership and contribution_recur tokens when passing a membership ID.
* This checks Bestspoke Tokens work correctly
*
* @return void
* @throws \API_Exception
* @throws \Civi\API\Exception\UnauthorizedException
*/
public function testRenderContributionRecurTokenFromMembership(): void {
$cid = $this->individualCreate();
$crid = \Civi\Api4\ContributionRecur::create(FALSE)
->addValue('contact_id', $cid)
->addValue('amount', 5)
->execute()
->first()['id'];
$mid = $this->contactMembershipCreate(['contribution_recur_id' => $crid, 'contact_id' => $cid]);

$tokenProcessor = new TokenProcessor(\Civi::dispatcher(), [
'controller' => __CLASS__,
'schema' => ['contactId', 'membershipId'],
'smarty' => FALSE,
]);
$tokenProcessor->addMessage('text', '!!{membership.id}{membership.contribution_recur_id.id}{membership.contribution_recur_id.amount}!!', 'text/plain');
$tokenProcessor->addRow()->context(['contactId' => $cid, 'membershipId' => $mid]);

$expectText = [
"!!{$mid}{$crid}$5.00!!",
];

$rowCount = 0;
foreach ($tokenProcessor->evaluate()->getRows() as $key => $row) {
/** @var TokenRow */
$this->assertTrue($row instanceof TokenRow);
$this->assertEquals($expectText[$key], $row->render('text'));
$rowCount++;
}
$this->assertEquals(1, $rowCount);
}

public function testGetMessageTokens(): void {
$tokenProcessor = $this->getTokenProcessor();
$tokenProcessor->addMessage('greeting_html', 'Good morning, <p>{contact.display_name}</p>. {custom.foobar}!', 'text/html');
Expand Down

0 comments on commit f030a44

Please sign in to comment.