Reconcile contribution amount tokens
[civicrm-core.git] / CRM / Contribute / Tokens.php
1 <?php
2
3 /*
4 +--------------------------------------------------------------------+
5 | Copyright CiviCRM LLC. All rights reserved. |
6 | |
7 | This work is published under the GNU AGPLv3 license with some |
8 | permitted exceptions and without any warranty. For full license |
9 | and copyright information, see https://civicrm.org/licensing |
10 +--------------------------------------------------------------------+
11 */
12
13 use Civi\ActionSchedule\Event\MailingQueryEvent;
14 use Civi\Token\TokenProcessor;
15 use Civi\Token\TokenRow;
16
17 /**
18 * Class CRM_Contribute_Tokens
19 *
20 * Generate "contribution.*" tokens.
21 *
22 * At time of writing, we don't have any particularly special tokens -- we just
23 * do some basic formatting based on the corresponding DB field.
24 */
25 class CRM_Contribute_Tokens extends CRM_Core_EntityTokens {
26
27 /**
28 * @return string
29 */
30 protected function getEntityName(): string {
31 return 'contribution';
32 }
33
34 /**
35 * Get the relevant bao name.
36 */
37 public function getBAOName(): string {
38 return CRM_Core_DAO_AllCoreTables::getFullName(ucfirst($this->getEntityName()));
39 }
40
41 /**
42 * Metadata about the entity fields.
43 *
44 * @var array
45 */
46 protected $fieldMetadata = [];
47
48 /**
49 * Get a list of tokens whose name and title match the DB fields.
50 * @return array
51 */
52 protected function getPassthruTokens(): array {
53 return [
54 'contribution_page_id',
55 'source',
56 'id',
57 'receive_date',
58 'total_amount',
59 'fee_amount',
60 'net_amount',
61 'non_deductible_amount',
62 'trxn_id',
63 'invoice_id',
64 'currency',
65 'cancel_date',
66 'receipt_date',
67 'thankyou_date',
68 'tax_amount',
69 'contribution_status_id',
70 'financial_type_id',
71 'payment_instrument_id',
72 ];
73 }
74
75 /**
76 * Get tokens supporting the syntax we are migrating to.
77 *
78 * In general these are tokens that were not previously supported
79 * so we can add them in the preferred way or that we have
80 * undertaken some, as yet to be written, db update.
81 *
82 * See https://lab.civicrm.org/dev/core/-/issues/2650
83 *
84 * @return string[]
85 */
86 public function getBasicTokens(): array {
87 $return = [];
88 foreach (['contribution_status_id', 'payment_instrument_id', 'financial_type_id', 'contribution_page_id'] as $fieldName) {
89 $return[$fieldName] = $this->getFieldMetadata()[$fieldName]['title'];
90 }
91 return $return;
92 }
93
94 /**
95 * Get pseudoTokens - it tokens that reflect the name or label of a pseudoconstant.
96 *
97 * @internal - this function will likely be made protected soon.
98 *
99 * @return array
100 */
101 public function getPseudoTokens(): array {
102 $return = [];
103 foreach (array_keys($this->getBasicTokens()) as $fieldName) {
104 if (!empty($this->fieldMetadata[$fieldName]['pseudoconstant'])) {
105 $return[$fieldName . ':label'] = $this->fieldMetadata[$fieldName]['html']['label'];
106 $return[$fieldName . ':name'] = ts('Machine name') . ': ' . $this->fieldMetadata[$fieldName]['html']['label'];
107 }
108 }
109 return $return;
110 }
111
112 /**
113 * Class constructor.
114 */
115 public function __construct() {
116 $tokens = CRM_Utils_Array::subset(
117 CRM_Utils_Array::collect('title', $this->getFieldMetadata()),
118 $this->getPassthruTokens()
119 );
120 $tokens = array_merge($tokens, $this->getPseudoTokens(), CRM_Utils_Token::getCustomFieldTokens('Contribution'));
121 parent::__construct('contribution', $tokens);
122 }
123
124 /**
125 * Check if the token processor is active.
126 *
127 * @param \Civi\Token\TokenProcessor $processor
128 *
129 * @return bool
130 */
131 public function checkActive(TokenProcessor $processor) {
132 return !empty($processor->context['actionMapping'])
133 && $processor->context['actionMapping']->getEntity() === 'civicrm_contribution';
134 }
135
136 /**
137 * Alter action schedule query.
138 *
139 * @param \Civi\ActionSchedule\Event\MailingQueryEvent $e
140 */
141 public function alterActionScheduleQuery(MailingQueryEvent $e): void {
142 if ($e->mapping->getEntity() !== 'civicrm_contribution') {
143 return;
144 }
145
146 $fields = $this->getFieldMetadata();
147 foreach ($this->getPassthruTokens() as $token) {
148 $e->query->select("e." . $fields[$token]['name'] . " AS contrib_{$token}");
149 }
150 foreach (array_keys($this->getPseudoTokens()) as $token) {
151 $split = explode(':', $token);
152 $e->query->select("e." . $fields[$split[0]]['name'] . " AS contrib_{$split[0]}");
153 }
154 }
155
156 /**
157 * @inheritDoc
158 * @throws \CRM_Core_Exception
159 */
160 public function evaluateToken(TokenRow $row, $entity, $field, $prefetch = NULL) {
161 $actionSearchResult = $row->context['actionSearchResult'];
162 $fieldValue = $actionSearchResult->{"contrib_$field"} ?? NULL;
163
164 if (array_key_exists($field, $this->getPseudoTokens())) {
165 $split = explode(':', $field);
166 return $row->tokens($entity, $field, $this->getPseudoValue($split[0], $split[1], $actionSearchResult->{"contrib_$split[0]"} ?? NULL));
167 }
168 if ($this->isMoneyField($field)) {
169 return $row->format('text/plain')->tokens($entity, $field,
170 \CRM_Utils_Money::format($fieldValue, $actionSearchResult->contrib_currency));
171 }
172 if ($this->isDateField($field)) {
173 return $row->format('text/plain')->tokens($entity, $field, \CRM_Utils_Date::customFormat($fieldValue));
174 }
175 if ($cfID = \CRM_Core_BAO_CustomField::getKeyID($field)) {
176 $row->customToken($entity, $cfID, $actionSearchResult->entity_id);
177 }
178 else {
179 $row->format('text/plain')->tokens($entity, $field, (string) $fieldValue);
180 }
181 }
182
183 /**
184 * Get the value for the relevant pseudo field.
185 *
186 * @param string $realField e.g contribution_status_id
187 * @param string $pseudoKey e.g name
188 * @param int|string $fieldValue e.g 1
189 *
190 * @return string
191 * Eg. 'Completed' in the example above.
192 *
193 * @internal function will likely be protected soon.
194 */
195 public function getPseudoValue(string $realField, string $pseudoKey, $fieldValue): string {
196 if ($pseudoKey === 'name') {
197 $fieldValue = (string) CRM_Core_PseudoConstant::getName($this->getBAOName(), $realField, $fieldValue);
198 }
199 if ($pseudoKey === 'label') {
200 $fieldValue = (string) CRM_Core_PseudoConstant::getLabel($this->getBAOName(), $realField, $fieldValue);
201 }
202 return (string) $fieldValue;
203 }
204
205 }