diff --git a/CRM/Contribute/Form/Task/PDFLetter.php b/CRM/Contribute/Form/Task/PDFLetter.php index e6b639f09e7c241809da57b7654658c45c233599..23df8d1a916041bcae669750b18629cf6f4d9f09 100644 --- a/CRM/Contribute/Form/Task/PDFLetter.php +++ b/CRM/Contribute/Form/Task/PDFLetter.php @@ -584,9 +584,7 @@ class CRM_Contribute_Form_Task_PDFLetter extends CRM_Contribute_Form_Task { foreach ($tokenProcessor->getRows() as $row) { $resolvedTokens[$token][$row->context['contributionId']] = $row->render($token); } - // We've resolved the value for each row - resorting to swapping them out - // with the old function. - $html_message = CRM_Utils_Token::token_replace('contribution', $token, implode($separator, $resolvedTokens[$token]), $html_message); + $html_message = str_replace('{contribution.' . $token . '}', implode($separator, $resolvedTokens[$token]), $html_message); } } $tokenContext['contributionId'] = $contributionID; diff --git a/CRM/Contribute/WorkflowMessage/RecurringEdit/AlexCancelled.ex.php b/CRM/Contribute/WorkflowMessage/RecurringEdit/AlexCancelled.ex.php index 057244938a4fd0a4a56a501777f070a49f4edc1e..846f99b1b0d6c31370c64fec26895b297e570caf 100644 --- a/CRM/Contribute/WorkflowMessage/RecurringEdit/AlexCancelled.ex.php +++ b/CRM/Contribute/WorkflowMessage/RecurringEdit/AlexCancelled.ex.php @@ -20,7 +20,7 @@ class CRM_Contribute_WorkflowMessage_RecurringEdit_AlexCancelled extends \Civi\W $example['asserts'] = [ 'default' => [ ['for' => 'subject', 'regex' => '/Recurring Contribution Update.*Alex/'], - ['for' => 'text', 'regex' => '/Recurring contribution is for € 5,990.99, every 2 year.s. for 24 installments/'], + ['for' => 'text', 'regex' => '/Recurring contribution is for €5,990.99, every 2 year.s. for 24 installments/'], ], ]; } diff --git a/CRM/Contribute/WorkflowMessage/RecurringEdit/BarbPending.ex.php b/CRM/Contribute/WorkflowMessage/RecurringEdit/BarbPending.ex.php index d6df8cb69ac9460390dabaec2dddfafd1ef9311e..6c19f770acadf44c1686600a837c160c7e8e3981 100644 --- a/CRM/Contribute/WorkflowMessage/RecurringEdit/BarbPending.ex.php +++ b/CRM/Contribute/WorkflowMessage/RecurringEdit/BarbPending.ex.php @@ -21,7 +21,7 @@ class CRM_Contribute_WorkflowMessage_RecurringEdit_BarbPending extends \Civi\Wor $example['asserts'] = [ 'default' => [ ['for' => 'subject', 'regex' => '/Recurring Contribution Update.*Barb/'], - ['for' => 'text', 'regex' => '/Recurring contribution is for € 5,990.99, every 2 year.s. for 24 installments/'], + ['for' => 'text', 'regex' => '/Recurring contribution is for €5,990.99, every 2 year.s. for 24 installments/'], ], ]; } diff --git a/CRM/Core/EntityTokens.php b/CRM/Core/EntityTokens.php index c1cb2fcbc414ac69a8eed4aa3b8981d5cea2a0f3..f995bc3650502bb3a0ec28706e0b99fb4066b1ec 100644 --- a/CRM/Core/EntityTokens.php +++ b/CRM/Core/EntityTokens.php @@ -16,6 +16,7 @@ use Civi\Token\Event\TokenValueEvent; use Civi\Token\TokenRow; use Civi\ActionSchedule\Event\MailingQueryEvent; use Civi\Token\TokenProcessor; +use Brick\Money\Money; /** * Class CRM_Core_EntityTokens @@ -123,8 +124,15 @@ class CRM_Core_EntityTokens extends AbstractTokenSubscriber { return $row->customToken($entity, \CRM_Core_BAO_CustomField::getKeyID($field), $this->getFieldValue($row, 'id')); } if ($this->isMoneyField($field)) { + $currency = $this->getCurrency($row); + if (!$currency) { + // too hard basket for now - just do what we always did. + return $row->format('text/plain')->tokens($entity, $field, + \CRM_Utils_Money::format($fieldValue, $currency)); + } return $row->format('text/plain')->tokens($entity, $field, - \CRM_Utils_Money::format($fieldValue, $this->getCurrency($row))); + Money::of($fieldValue, $currency)); + } if ($this->isDateField($field)) { try { diff --git a/Civi/Token/TokenCompatSubscriber.php b/Civi/Token/TokenCompatSubscriber.php index 33e394f3cdfca0522db59454b222ab153c4bddd1..6274d8f29c399e72ee6d9bfe17ee78b0559f8c1e 100644 --- a/Civi/Token/TokenCompatSubscriber.php +++ b/Civi/Token/TokenCompatSubscriber.php @@ -3,6 +3,7 @@ namespace Civi\Token; use Civi\Token\Event\TokenRenderEvent; use Civi\Token\Event\TokenValueEvent; +use Money\Money; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -69,7 +70,10 @@ class TokenCompatSubscriber implements EventSubscriberInterface { if ($useSmarty) { $smartyVars = []; foreach ($e->context['smartyTokenAlias'] ?? [] as $smartyName => $tokenName) { - $smartyVars[$smartyName] = \CRM_Utils_Array::pathGet($e->row->tokens, explode('.', $tokenName)); + $smartyVars[$smartyName] = \CRM_Utils_Array::pathGet($e->row->tokens, explode('.', $tokenName), $e->context['locale'] ?? NULL); + if ($smartyVars[$smartyName] instanceof \Brick\Money\Money) { + $smartyVars[$smartyName] = \Civi::format()->money($smartyVars[$smartyName]->getAmount(), $smartyVars[$smartyName]->getCurrency()); + } } \CRM_Core_Smarty::singleton()->pushScope($smartyVars); try { diff --git a/Civi/Token/TokenProcessor.php b/Civi/Token/TokenProcessor.php index f2e32add916835563472714784440adbd5ee2d2a..0451b2ae531ea55e71abb5b8623bd357e97d5a37 100644 --- a/Civi/Token/TokenProcessor.php +++ b/Civi/Token/TokenProcessor.php @@ -1,6 +1,7 @@ <?php namespace Civi\Token; +use Brick\Money\Money; use Civi\Token\Event\TokenRegisterEvent; use Civi\Token\Event\TokenRenderEvent; use Civi\Token\Event\TokenValueEvent; @@ -429,7 +430,7 @@ class TokenProcessor { '/:"([^"]+)"/' => $enqueue, ], $m[3]); if ($unmatched) { - throw new \CRM_Core_Exception("Malformed token parameters (" . $m[0] . ")"); + throw new \CRM_Core_Exception('Malformed token parameters (' . $m[0] . ')'); } } return $callback($m[0] ?? NULL, $m[1] ?? NULL, $m[2] ?? NULL, $filterParts); @@ -458,6 +459,10 @@ class TokenProcessor { } } + if ($value instanceof Money && $filter === NULL) { + $filter = ['crmMoney']; + } + switch ($filter[0] ?? NULL) { case NULL: return $value; @@ -468,6 +473,11 @@ class TokenProcessor { case 'lower': return mb_strtolower($value); + case 'crmMoney': + if ($value instanceof Money) { + return \Civi::format()->money($value->getAmount(), $value->getCurrency()); + } + case 'crmDate': if ($value instanceof \DateTime) { // @todo cludgey. diff --git a/Civi/Token/TokenRow.php b/Civi/Token/TokenRow.php index 680e7c0e36936e375a087bb08c0cc967f8489b8b..11be3a3ba1ffdd6eda8b5752de93490a21f070e3 100644 --- a/Civi/Token/TokenRow.php +++ b/Civi/Token/TokenRow.php @@ -1,8 +1,11 @@ <?php namespace Civi\Token; +use Brick\Money\Money; + /** * Class TokenRow + * * @package Civi\Token * * A TokenRow is a helper/stub providing simplified access to the TokenProcessor. @@ -283,7 +286,7 @@ class TokenRow { // HTML => Plain. foreach ($htmlTokens as $entity => $values) { foreach ($values as $field => $value) { - if (!$value instanceof \DateTime) { + if (!$value instanceof \DateTime && !$value instanceof Money) { $value = html_entity_decode(strip_tags($value)); } if (!isset($textTokens[$entity][$field])) { diff --git a/tests/phpunit/CRM/Contribute/ActionMapping/ByTypeTest.php b/tests/phpunit/CRM/Contribute/ActionMapping/ByTypeTest.php index fa2a50b8dbc95ca0293b8c97ba6e51c6937a6800..44c47552be1686495ef12a9bbb6b7a5c922f2791 100644 --- a/tests/phpunit/CRM/Contribute/ActionMapping/ByTypeTest.php +++ b/tests/phpunit/CRM/Contribute/ActionMapping/ByTypeTest.php @@ -311,10 +311,10 @@ class CRM_Contribute_ActionMapping_ByTypeTest extends \Civi\ActionSchedule\Abstr 'payment instrument id = 4', 'payment instrument name = Check', 'payment instrument label = Check', - 'non_deductible_amount = € 10.00', - 'total_amount = € 100.00', - 'net_amount = € 95.00', - 'fee_amount = € 5.00', + 'non_deductible_amount = €10.00', + 'total_amount = €100.00', + 'net_amount = €95.00', + 'fee_amount = €5.00', 'campaign_id = 1', 'campaign name = big_campaign', 'campaign label = Campaign', diff --git a/tests/phpunit/CRM/Contribute/Form/Task/EmailTest.php b/tests/phpunit/CRM/Contribute/Form/Task/EmailTest.php index e3cdc9ffc7efe5b7e5ad8dc1230a3ce4ec073fb3..8211eae5a628b46235efc02843042ac394d903d6 100644 --- a/tests/phpunit/CRM/Contribute/Form/Task/EmailTest.php +++ b/tests/phpunit/CRM/Contribute/Form/Task/EmailTest.php @@ -70,10 +70,10 @@ class CRM_Contribute_Form_Task_EmailTest extends CiviUnitTestCase { $form->buildForm(); $this->assertEquals('<br/><br/>--Benny, Benny', $form->_defaultValues['html_message']); $form->postProcess(); - $mut->assertSubjects(['Mr. Anthony Anderson II $ 999.00', 'Mr. Elton Anderson II $ 100.00']); + $mut->assertSubjects(['Mr. Anthony Anderson II $999.00', 'Mr. Elton Anderson II $100.00']); $mut->checkAllMailLog([ 'Subject: Mr. Anthony Anderson II', - '$ 999.0', + '$999.0', 'Default Domain Name', 'Donation soy', 'Donation ranch', diff --git a/tests/phpunit/CRM/Contribute/Form/Task/PDFLetterCommonTest.php b/tests/phpunit/CRM/Contribute/Form/Task/PDFLetterCommonTest.php index 54250b806d731f3e268642b7cea8f4b8b0725934..91e06ed8fb4b8e70ba60a644257b891f90119c21 100644 --- a/tests/phpunit/CRM/Contribute/Form/Task/PDFLetterCommonTest.php +++ b/tests/phpunit/CRM/Contribute/Form/Task/PDFLetterCommonTest.php @@ -105,7 +105,7 @@ class CRM_Contribute_Form_Task_PDFLetterCommonTest extends CiviUnitTestCase { $form->postProcess(); } catch (CRM_Core_Exception_PrematureExitException $e) { - $this->assertStringContainsString('USD, USD * $ 60.00, $ 70.00 * January 1st, 2021 1:21 PM, February 1st, 2021 2:21 AM', $e->errorData['html']); + $this->assertStringContainsString('USD, USD * $60.00, $70.00 * January 1st, 2021 1:21 PM, February 1st, 2021 2:21 AM', $e->errorData['html']); } } @@ -198,7 +198,6 @@ class CRM_Contribute_Form_Task_PDFLetterCommonTest extends CiviUnitTestCase { $this->createLoggedInUser();; foreach (['docx', 'odt'] as $docType) { $formValues = [ - 'is_unit_test' => TRUE, 'group_by' => NULL, 'document_file' => [ 'name' => __DIR__ . "/sample_documents/Template.$docType", @@ -297,10 +296,10 @@ class CRM_Contribute_Form_Task_PDFLetterCommonTest extends CiviUnitTestCase { <body> <div id="crm-container"> id : 1 -total_amount : € 9,999.99 -fee_amount : € 1,111.11 -net_amount : € 7,777.78 -non_deductible_amount : € 2,222.22 +total_amount : €9,999.99 +fee_amount : €1,111.11 +net_amount : €7,777.78 +non_deductible_amount : €2,222.22 receive_date : July 20th, 2018 payment_instrument_id:label : Check trxn_id : 1234 diff --git a/tests/phpunit/CRM/Contribute/Form/UpdateSubscriptionTest.php b/tests/phpunit/CRM/Contribute/Form/UpdateSubscriptionTest.php index d758acedfe470ea72b7be96d0eac7fc74fb5d2fd..7cb3d3ee529faf26c8b0b0abb86fb78f97fd1ae7 100644 --- a/tests/phpunit/CRM/Contribute/Form/UpdateSubscriptionTest.php +++ b/tests/phpunit/CRM/Contribute/Form/UpdateSubscriptionTest.php @@ -50,7 +50,7 @@ class CRM_Contribute_Form_UpdateSubscriptionTest extends CRM_Contribute_Form_Rec 'Return-Path: bob@example.org', 'Dear Anthony,', 'Your recurring contribution has been updated as requested:', - 'Recurring contribution is for $ 10.00, every 1 month(s) for 12 installments.', + 'Recurring contribution is for $10.00, every 1 month(s) for 12 installments.', 'If you have questions please contact us at "Bob" <bob@example.org>.', ]; } diff --git a/tests/phpunit/CRM/Utils/TokenConsistencyTest.php b/tests/phpunit/CRM/Utils/TokenConsistencyTest.php index e5878ab7848e99c2ddd13388c07c5821a3f8f964..1fe92bae983a11c290bf96dd72c682fe0747ef86 100644 --- a/tests/phpunit/CRM/Utils/TokenConsistencyTest.php +++ b/tests/phpunit/CRM/Utils/TokenConsistencyTest.php @@ -47,6 +47,7 @@ class CRM_Utils_TokenConsistencyTest extends CiviUnitTestCase { */ public function tearDown(): void { $this->quickCleanup(['civicrm_case', 'civicrm_case_type', 'civicrm_participant', 'civicrm_event'], TRUE); + $this->quickCleanUpFinancialEntities(); parent::tearDown(); } @@ -206,6 +207,28 @@ case.custom_1 :' . ' $this->assertEquals($this->getExpectedContributionRecurTokenOutPut(), $tokenProcessor->getRow(0)->render('html')); } + /** + * Test money format tokens can respect passed in locale. + */ + public function testMoneyFormat(): void { + // Our 'migration' off configured thousand separators at the moment is a define. + putenv('IGNORE_SEPARATOR_CONFIG=1'); + $this->createLoggedInUser(); + $tokenProcessor = new TokenProcessor(\Civi::dispatcher(), [ + 'controller' => __CLASS__, + 'smarty' => FALSE, + 'schema' => ['contribution_recurId'], + ]); + $tokenString = '{contribution_recur.amount}'; + $tokenProcessor->addMessage('html', $tokenString, 'text/plain'); + $tokenProcessor->addRow([ + 'contribution_recurId' => $this->getContributionRecurID(), + 'locale' => 'nb_NO', + ]); + $tokenProcessor->evaluate(); + $this->assertEquals('€ 5 990,99', $tokenProcessor->getRow(0)->render('html')); + } + /** * Get tokens that are not advertised via listTokens. * @@ -379,7 +402,7 @@ case.custom_1 :' . ' */ protected function getExpectedContributionRecurTokenOutPut(): string { return 'contribution_recur.id :' . $this->getContributionRecurID() . ' -contribution_recur.amount :€ 5,990.99 +contribution_recur.amount :€5,990.99 contribution_recur.currency :EUR contribution_recur.frequency_unit :year contribution_recur.frequency_interval :2 @@ -533,7 +556,7 @@ participant.role_id :1 participant.register_date :February 19th, 2007 participant.source :Wimbeldon participant.fee_level :steep -participant.fee_amount :$ 50.00 +participant.fee_amount :$50.00 participant.registered_by_id : participant.transferred_to_contact_id : participant.role_id:label :Attendee