Merge pull request #21460 from civicrm/5.42
[civicrm-core.git] / ext / financialacls / financialacls.php
CommitLineData
e7339d59 1<?php
2
3require_once 'financialacls.civix.php';
4// phpcs:disable
5use CRM_Financialacls_ExtensionUtil as E;
6// phpcs:enable
7
8/**
9 * Implements hook_civicrm_config().
10 *
11 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_config/
12 */
13function financialacls_civicrm_config(&$config) {
14 _financialacls_civix_civicrm_config($config);
15}
16
af4cccf7
TO
17/**
18 * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
19 */
20function financialacls_civicrm_container($container) {
21 $dispatcherDefn = $container->getDefinition('dispatcher');
22 $container->addResource(new \Symfony\Component\Config\Resource\FileResource(__FILE__));
23 $dispatcherDefn->addMethodCall('addListener', ['civi.api4.authorizeRecord::Contribution', '_financialacls_civi_api4_authorizeContribution']);
24}
25
e7339d59 26/**
27 * Implements hook_civicrm_xmlMenu().
28 *
29 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_xmlMenu
30 */
31function financialacls_civicrm_xmlMenu(&$files) {
32 _financialacls_civix_civicrm_xmlMenu($files);
33}
34
35/**
36 * Implements hook_civicrm_install().
37 *
38 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_install
39 */
40function financialacls_civicrm_install() {
41 _financialacls_civix_civicrm_install();
42}
43
44/**
45 * Implements hook_civicrm_postInstall().
46 *
47 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_postInstall
48 */
49function financialacls_civicrm_postInstall() {
50 _financialacls_civix_civicrm_postInstall();
51}
52
53/**
54 * Implements hook_civicrm_uninstall().
55 *
56 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_uninstall
57 */
58function financialacls_civicrm_uninstall() {
59 _financialacls_civix_civicrm_uninstall();
60}
61
62/**
63 * Implements hook_civicrm_enable().
64 *
65 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_enable
66 */
67function financialacls_civicrm_enable() {
68 _financialacls_civix_civicrm_enable();
69}
70
71/**
72 * Implements hook_civicrm_disable().
73 *
74 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_disable
75 */
76function financialacls_civicrm_disable() {
77 _financialacls_civix_civicrm_disable();
78}
79
80/**
81 * Implements hook_civicrm_upgrade().
82 *
83 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_upgrade
84 */
85function financialacls_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) {
86 return _financialacls_civix_civicrm_upgrade($op, $queue);
87}
88
89/**
90 * Implements hook_civicrm_managed().
91 *
92 * Generate a list of entities to create/deactivate/delete when this module
93 * is installed, disabled, uninstalled.
94 *
95 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_managed
96 */
97function financialacls_civicrm_managed(&$entities) {
98 _financialacls_civix_civicrm_managed($entities);
99}
100
101/**
102 * Implements hook_civicrm_caseTypes().
103 *
104 * Generate a list of case-types.
105 *
106 * Note: This hook only runs in CiviCRM 4.4+.
107 *
108 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_caseTypes
109 */
110function financialacls_civicrm_caseTypes(&$caseTypes) {
111 _financialacls_civix_civicrm_caseTypes($caseTypes);
112}
113
114/**
115 * Implements hook_civicrm_angularModules().
116 *
117 * Generate a list of Angular modules.
118 *
119 * Note: This hook only runs in CiviCRM 4.5+. It may
120 * use features only available in v4.6+.
121 *
122 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_angularModules
123 */
124function financialacls_civicrm_angularModules(&$angularModules) {
125 _financialacls_civix_civicrm_angularModules($angularModules);
126}
127
128/**
129 * Implements hook_civicrm_alterSettingsFolders().
130 *
131 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_alterSettingsFolders
132 */
133function financialacls_civicrm_alterSettingsFolders(&$metaDataFolders = NULL) {
134 _financialacls_civix_civicrm_alterSettingsFolders($metaDataFolders);
135}
136
137/**
138 * Implements hook_civicrm_entityTypes().
139 *
140 * Declare entity types provided by this module.
141 *
142 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_entityTypes
143 */
144function financialacls_civicrm_entityTypes(&$entityTypes) {
145 _financialacls_civix_civicrm_entityTypes($entityTypes);
146}
147
148/**
149 * Implements hook_civicrm_thems().
150 */
151function financialacls_civicrm_themes(&$themes) {
152 _financialacls_civix_civicrm_themes($themes);
153}
154
b82fb202 155/**
156 * Intervene to prevent deletion, where permissions block it.
157 *
aeee327d 158 * @param string $op
b82fb202 159 * @param string $objectName
160 * @param int|null $id
161 * @param array $params
162 *
163 * @throws \API_Exception
164 * @throws \CRM_Core_Exception
165 */
166function financialacls_civicrm_pre($op, $objectName, $id, &$params) {
34509ae3 167 if (!financialacls_is_acl_limiting_enabled()) {
168 return;
169 }
aeee327d 170 if ($objectName === 'LineItem' && !empty($params['check_permissions'])) {
34509ae3 171 $operationMap = ['delete' => CRM_Core_Action::DELETE, 'edit' => CRM_Core_Action::UPDATE, 'create' => CRM_Core_Action::ADD];
172 CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes($types, $operationMap[$op]);
173 if (empty($params['financial_type_id'])) {
174 $params['financial_type_id'] = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_LineItem', $params['id'], 'financial_type_id');
175 }
c3f7ab62 176 if (!array_key_exists($params['financial_type_id'], $types)) {
34509ae3 177 throw new API_Exception('You do not have permission to ' . $op . ' this line item');
b82fb202 178 }
179 }
d646594f 180 if ($objectName === 'FinancialType' && !empty($params['id']) && !empty($params['name'])) {
181 $prevName = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', $params['id']);
182 if ($prevName !== $params['name']) {
183 CRM_Core_Session::setStatus(ts("Changing the name of a Financial Type will result in losing the current permissions associated with that Financial Type.
184 Before making this change you should likely note the existing permissions at Administer > Users and Permissions > Permissions (Access Control),
185 then clicking the Access Control link for your Content Management System, then noting down the permissions for 'CiviCRM: {financial type name} view', etc.
186 Then after making the change of name, reset the permissions to the way they were."), ts('Warning'), 'warning');
187 }
188 }
b82fb202 189}
190
28188a1e 191/**
192 * Implements hook_civicrm_selectWhereClause().
193 *
194 * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_selectWhereClause
195 */
196function financialacls_civicrm_selectWhereClause($entity, &$clauses) {
34509ae3 197 if (!financialacls_is_acl_limiting_enabled()) {
198 return;
199 }
2dc76e8d
MW
200
201 switch ($entity) {
202 case 'LineItem':
203 case 'MembershipType':
f4a72e8d 204 case 'ContributionRecur':
2dc76e8d
MW
205 $types = [];
206 CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes($types);
207 if ($types) {
208 $clauses['financial_type_id'] = 'IN (' . implode(',', array_keys($types)) . ')';
209 }
210 else {
211 $clauses['financial_type_id'] = '= 0';
212 }
213 break;
214
28188a1e 215 }
216
217}
218
07d89c14 219/**
34509ae3 220 * Remove unpermitted options.
07d89c14 221 *
222 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_buildAmount
223 *
224 * @param string $component
225 * @param \CRM_Core_Form $form
226 * @param array $feeBlock
227 */
228function financialacls_civicrm_buildAmount($component, $form, &$feeBlock) {
34509ae3 229 if (!financialacls_is_acl_limiting_enabled()) {
230 return;
231 }
232
233 foreach ($feeBlock as $key => $value) {
234 foreach ($value['options'] as $k => $options) {
235 if (!CRM_Core_Permission::check('add contributions of type ' . CRM_Contribute_PseudoConstant::financialType($options['financial_type_id']))) {
236 unset($feeBlock[$key]['options'][$k]);
07d89c14 237 }
238 }
34509ae3 239 if (empty($feeBlock[$key]['options'])) {
240 unset($feeBlock[$key]);
241 }
07d89c14 242 }
243}
244
e9eed3db 245/**
246 * Remove unpermitted membership types from selection availability..
247 *
248 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_membershipTypeValues
249 *
250 * @param \CRM_Core_Form $form
251 * @param array $membershipTypeValues
252 */
253function financialacls_civicrm_membershipTypeValues($form, &$membershipTypeValues) {
34509ae3 254 if (!financialacls_is_acl_limiting_enabled()) {
255 return;
256 }
e9eed3db 257 $financialTypes = NULL;
258 $financialTypes = CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes($financialTypes, CRM_Core_Action::ADD);
259 foreach ($membershipTypeValues as $id => $type) {
260 if (!isset($financialTypes[$type['financial_type_id']])) {
261 unset($membershipTypeValues[$id]);
262 }
263 }
264}
265
4e0bf3e8 266/**
267 * Add permissions.
268 *
269 * @see https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_permission/
270 *
271 * @param array $permissions
272 */
273function financialacls_civicrm_permission(&$permissions) {
274 if (!financialacls_is_acl_limiting_enabled()) {
275 return;
276 }
277 $actions = [
278 'add' => ts('add'),
279 'view' => ts('view'),
280 'edit' => ts('edit'),
281 'delete' => ts('delete'),
282 ];
283 $financialTypes = \CRM_Contribute_BAO_Contribution::buildOptions('financial_type_id', 'validate');
284 foreach ($financialTypes as $id => $type) {
285 foreach ($actions as $action => $action_ts) {
286 $permissions[$action . ' contributions of type ' . $type] = [
287 ts("CiviCRM: %1 contributions of type %2", [1 => $action_ts, 2 => $type]),
288 ts('%1 contributions of type %2', [1 => $action_ts, 2 => $type]),
289 ];
290 }
291 }
292 $permissions['administer CiviCRM Financial Types'] = [
293 ts('CiviCRM: administer CiviCRM Financial Types'),
294 ts('Administer access to Financial Types'),
295 ];
296}
297
9cef6066 298/**
af4cccf7 299 * Listener for 'civi.api4.authorizeRecord::Contribution'
9cef6066 300 *
af4cccf7 301 * @param \Civi\Api4\Event\AuthorizeRecordEvent $e
9cef6066 302 * @throws \CRM_Core_Exception
303 */
af4cccf7 304function _financialacls_civi_api4_authorizeContribution(\Civi\Api4\Event\AuthorizeRecordEvent $e) {
9cef6066 305 if (!financialacls_is_acl_limiting_enabled()) {
306 return;
307 }
0552d667
EM
308 if ($e->getEntityName() === 'Contribution') {
309 $contributionID = $e->getRecord()['id'] ?? NULL;
310 $financialTypeID = $e->getRecord()['financial_type_id'] ?? CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $contributionID, 'financial_type_id');
311 if (!CRM_Core_Permission::check(_financialacls_getRequiredPermission($financialTypeID, $e->getActionName()), $e->getUserID())) {
af4cccf7 312 $e->setAuthorized(FALSE);
9cef6066 313 }
0552d667
EM
314 if ($e->getActionName() === 'delete') {
315 // First check contribution financial type
316 // Now check permissioned line items & permissioned contribution
317 if (!CRM_Financial_BAO_FinancialType::checkPermissionedLineItems($contributionID, 'delete', FALSE, $e->getUserID())
318 ) {
319 $e->setAuthorized(FALSE);
320 }
321 }
9cef6066 322 }
323}
324
0552d667
EM
325/**
326 * Get the permission required to perform this action on this financial type.
327 *
328 * @param int $financialTypeID
329 * @param string $action
330 *
331 * @return string
332 */
333function _financialacls_getRequiredPermission(int $financialTypeID, string $action): string {
334 $financialType = CRM_Core_PseudoConstant::getName('CRM_Contribute_DAO_Contribution', 'financial_type_id', $financialTypeID);
335 $actionMap = [
336 'create' => 'add',
337 'update' => 'edit',
338 'delete' => 'delete',
339 ];
340 return $actionMap[$action] . ' contributions of type ' . $financialType;
341}
342
51d1f926 343/**
344 * Remove unpermitted financial types from field Options in search context.
345 *
346 * Search context is described as
347 * 'search' => "search: searchable options are returned; labels are translated.",
348 * So this is appropriate to removing the options from search screens.
349 *
350 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_fieldOptions
351 *
352 * @param string $entity
353 * @param string $field
354 * @param array $options
355 * @param array $params
356 */
357function financialacls_civicrm_fieldOptions($entity, $field, &$options, $params) {
34509ae3 358 if (!financialacls_is_acl_limiting_enabled()) {
359 return;
360 }
f4a72e8d 361 if (in_array($entity, ['Contribution', 'ContributionRecur'], TRUE) && $field === 'financial_type_id' && $params['context'] === 'search') {
51d1f926 362 $action = CRM_Core_Action::VIEW;
363 // At this stage we are only considering the view action. Code from
364 // CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes().
365 $actions = [
366 CRM_Core_Action::VIEW => 'view',
367 CRM_Core_Action::UPDATE => 'edit',
368 CRM_Core_Action::ADD => 'add',
369 CRM_Core_Action::DELETE => 'delete',
370 ];
371 $cacheKey = 'available_types_' . $action;
372 if (!isset(\Civi::$statics['CRM_Financial_BAO_FinancialType'][$cacheKey])) {
373 foreach ($options as $finTypeId => $type) {
374 if (!CRM_Core_Permission::check($actions[$action] . ' contributions of type ' . $type)) {
375 unset($options[$finTypeId]);
376 }
377 }
378 \Civi::$statics['CRM_Financial_BAO_FinancialType'][$cacheKey] = $options;
379 }
380 $options = \Civi::$statics['CRM_Financial_BAO_FinancialType'][$cacheKey];
381 }
382}
383
34509ae3 384/**
385 * Is financial acl limiting enabled.
386 *
387 * Once this extension is detangled enough to be optional this will go
388 * and the status of the extension rather than the setting will dictate.
389 *
390 * @return bool
391 */
d646594f 392function financialacls_is_acl_limiting_enabled(): bool {
34509ae3 393 return (bool) Civi::settings()->get('acl_financial_type');
394}
395
a572646e
EM
396/**
397 * Clear the statics cache when the setting is enabled or disabled.
398 *
399 * Note the setting will eventually disappear in favour of whether
400 * the extension is enabled or disabled.
401 */
402function financialacls_toggle() {
403 unset(\Civi::$statics['CRM_Financial_BAO_FinancialType']);
404}
405
e7339d59 406// --- Functions below this ship commented out. Uncomment as required. ---
407
408/**
409 * Implements hook_civicrm_preProcess().
410 *
411 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_preProcess
412 */
413//function financialacls_civicrm_preProcess($formName, &$form) {
414//
415//}
416
417/**
418 * Implements hook_civicrm_navigationMenu().
419 *
420 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_navigationMenu
421 */
422//function financialacls_civicrm_navigationMenu(&$menu) {
423// _financialacls_civix_insert_navigation_menu($menu, 'Mailings', array(
424// 'label' => E::ts('New subliminal message'),
425// 'name' => 'mailing_subliminal_message',
426// 'url' => 'civicrm/mailing/subliminal',
427// 'permission' => 'access CiviMail',
428// 'operator' => 'OR',
429// 'separator' => 0,
430// ));
431// _financialacls_civix_navigationMenu($menu);
432//}