3 require_once 'financialacls.civix.php';
5 use Civi\Api4\EntityFinancialAccount
;
6 use CRM_Financialacls_ExtensionUtil
as E
;
10 * Implements hook_civicrm_config().
12 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_config/
14 function financialacls_civicrm_config(&$config) {
15 _financialacls_civix_civicrm_config($config);
19 * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
21 function financialacls_civicrm_container($container) {
22 $dispatcherDefn = $container->getDefinition('dispatcher');
23 $container->addResource(new \Symfony\Component\Config\
Resource\
FileResource(__FILE__
));
24 $dispatcherDefn->addMethodCall('addListener', ['civi.api4.authorizeRecord::Contribution', '_financialacls_civi_api4_authorizeContribution']);
28 * Implements hook_civicrm_install().
30 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_install
32 function financialacls_civicrm_install() {
33 _financialacls_civix_civicrm_install();
37 * Implements hook_civicrm_postInstall().
39 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_postInstall
41 function financialacls_civicrm_postInstall() {
42 _financialacls_civix_civicrm_postInstall();
46 * Implements hook_civicrm_uninstall().
48 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_uninstall
50 function financialacls_civicrm_uninstall() {
51 _financialacls_civix_civicrm_uninstall();
55 * Implements hook_civicrm_enable().
57 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_enable
59 function financialacls_civicrm_enable() {
60 _financialacls_civix_civicrm_enable();
64 * Implements hook_civicrm_disable().
66 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_disable
68 function financialacls_civicrm_disable() {
69 _financialacls_civix_civicrm_disable();
73 * Implements hook_civicrm_upgrade().
75 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_upgrade
77 function financialacls_civicrm_upgrade($op, CRM_Queue_Queue
$queue = NULL) {
78 return _financialacls_civix_civicrm_upgrade($op, $queue);
82 * Implements hook_civicrm_entityTypes().
84 * Declare entity types provided by this module.
86 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_entityTypes
88 function financialacls_civicrm_entityTypes(&$entityTypes) {
89 _financialacls_civix_civicrm_entityTypes($entityTypes);
93 * Intervene to prevent deletion, where permissions block it.
96 * @param string $objectName
98 * @param array $params
100 * @throws \API_Exception
101 * @throws \CRM_Core_Exception
103 function financialacls_civicrm_pre($op, $objectName, $id, &$params) {
104 if (!financialacls_is_acl_limiting_enabled()) {
107 if ($objectName === 'LineItem' && !empty($params['check_permissions'])) {
108 $operationMap = ['delete' => CRM_Core_Action
::DELETE
, 'edit' => CRM_Core_Action
::UPDATE
, 'create' => CRM_Core_Action
::ADD
];
109 CRM_Financial_BAO_FinancialType
::getAvailableFinancialTypes($types, $operationMap[$op]);
110 if (empty($params['financial_type_id'])) {
111 $params['financial_type_id'] = CRM_Core_DAO
::getFieldValue('CRM_Price_DAO_LineItem', $params['id'], 'financial_type_id');
113 if (!array_key_exists($params['financial_type_id'], $types)) {
114 throw new API_Exception('You do not have permission to ' . $op . ' this line item');
117 if ($objectName === 'FinancialType' && !empty($params['id']) && !empty($params['name'])) {
118 $prevName = CRM_Core_DAO
::getFieldValue('CRM_Financial_DAO_FinancialType', $params['id']);
119 if ($prevName !== $params['name']) {
120 CRM_Core_Session
::setStatus(ts("Changing the name of a Financial Type will result in losing the current permissions associated with that Financial Type.
121 Before making this change you should likely note the existing permissions at Administer > Users and Permissions > Permissions (Access Control),
122 then clicking the Access Control link for your Content Management System, then noting down the permissions for 'CiviCRM: {financial type name} view', etc.
123 Then after making the change of name, reset the permissions to the way they were."), ts('Warning'), 'warning');
129 * Implements hook_civicrm_selectWhereClause().
131 * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_selectWhereClause
133 function financialacls_civicrm_selectWhereClause($entity, &$clauses) {
134 if (!financialacls_is_acl_limiting_enabled()) {
140 case 'MembershipType':
141 case 'ContributionRecur':
143 $clauses['financial_type_id'] = _financialacls_civicrm_get_type_clause();
146 case 'FinancialType':
147 $clauses['id'] = _financialacls_civicrm_get_type_clause();
150 case 'FinancialAccount':
151 $clauses['id'] = _financialacls_civicrm_get_accounts_clause();
159 * Get the clause to limit available types.
163 function _financialacls_civicrm_get_accounts_clause(): string {
164 if (!isset(Civi
::$statics['financial_acls'][__FUNCTION__
][CRM_Core_Session
::getLoggedInContactID()])) {
167 Civi
::$statics['financial_acls'][__FUNCTION__
][CRM_Core_Session
::getLoggedInContactID()] = &$clause;
168 $accounts = (array) EntityFinancialAccount
::get()
169 ->addWhere('account_relationship:name', '=', 'Income Account is')
170 ->addWhere('entity_table', '=', 'civicrm_financial_type')
171 ->addSelect('entity_id', 'financial_account_id')
172 ->addJoin('FinancialType AS financial_type', 'LEFT', [
177 ->execute()->indexBy('financial_account_id');
178 if (!empty($accounts)) {
179 $clause = 'IN (' . implode(',', array_keys($accounts)) . ')';
182 catch (\API_Exception
$e) {
183 // We've already set it to 0 so we can quietly handle this.
186 return Civi
::$statics['financial_acls'][__FUNCTION__
][CRM_Core_Session
::getLoggedInContactID()];
190 * Get the clause to limit available types.
194 function _financialacls_civicrm_get_type_clause(): string {
196 CRM_Financial_BAO_FinancialType
::getAvailableFinancialTypes($types);
198 return 'IN (' . implode(',', array_keys($types)) . ')';
204 * Remove unpermitted options.
206 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_buildAmount
208 * @param string $component
209 * @param \CRM_Core_Form $form
210 * @param array $feeBlock
212 function financialacls_civicrm_buildAmount($component, $form, &$feeBlock) {
213 if (!financialacls_is_acl_limiting_enabled()) {
217 foreach ($feeBlock as $key => $value) {
218 foreach ($value['options'] as $k => $options) {
219 if (!CRM_Core_Permission
::check('add contributions of type ' . CRM_Contribute_PseudoConstant
::financialType($options['financial_type_id']))) {
220 unset($feeBlock[$key]['options'][$k]);
223 if (empty($feeBlock[$key]['options'])) {
224 unset($feeBlock[$key]);
230 * Remove unpermitted membership types from selection availability..
232 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_membershipTypeValues
234 * @param \CRM_Core_Form $form
235 * @param array $membershipTypeValues
237 function financialacls_civicrm_membershipTypeValues($form, &$membershipTypeValues) {
238 if (!financialacls_is_acl_limiting_enabled()) {
241 $financialTypes = NULL;
242 $financialTypes = CRM_Financial_BAO_FinancialType
::getAvailableFinancialTypes($financialTypes, CRM_Core_Action
::ADD
);
243 foreach ($membershipTypeValues as $id => $type) {
244 if (!isset($financialTypes[$type['financial_type_id']])) {
245 unset($membershipTypeValues[$id]);
253 * @see https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_permission/
255 * @param array $permissions
257 function financialacls_civicrm_permission(&$permissions) {
258 if (!financialacls_is_acl_limiting_enabled()) {
263 'view' => ts('view'),
264 'edit' => ts('edit'),
265 'delete' => ts('delete'),
267 $financialTypes = \CRM_Contribute_BAO_Contribution
::buildOptions('financial_type_id', 'validate');
268 foreach ($financialTypes as $id => $type) {
269 foreach ($actions as $action => $action_ts) {
270 $permissions[$action . ' contributions of type ' . $type] = [
271 ts("CiviCRM: %1 contributions of type %2", [1 => $action_ts, 2 => $type]),
272 ts('%1 contributions of type %2', [1 => $action_ts, 2 => $type]),
276 $permissions['administer CiviCRM Financial Types'] = [
277 ts('CiviCRM: administer CiviCRM Financial Types'),
278 ts('Administer access to Financial Types'),
283 * Listener for 'civi.api4.authorizeRecord::Contribution'
285 * @param \Civi\Api4\Event\AuthorizeRecordEvent $e
286 * @throws \CRM_Core_Exception
288 function _financialacls_civi_api4_authorizeContribution(\Civi\Api4\Event\AuthorizeRecordEvent
$e) {
289 if (!financialacls_is_acl_limiting_enabled()) {
292 if ($e->getEntityName() === 'Contribution') {
293 $contributionID = $e->getRecord()['id'] ??
NULL;
294 $financialTypeID = $e->getRecord()['financial_type_id'] ?? CRM_Core_DAO
::getFieldValue('CRM_Contribute_DAO_Contribution', $contributionID, 'financial_type_id');
295 if (!CRM_Core_Permission
::check(_financialacls_getRequiredPermission($financialTypeID, $e->getActionName()), $e->getUserID())) {
296 $e->setAuthorized(FALSE);
298 if ($e->getActionName() === 'delete') {
299 // First check contribution financial type
300 // Now check permissioned line items & permissioned contribution
301 if (!CRM_Financial_BAO_FinancialType
::checkPermissionedLineItems($contributionID, 'delete', FALSE, $e->getUserID())
303 $e->setAuthorized(FALSE);
310 * Get the permission required to perform this action on this financial type.
312 * @param int $financialTypeID
313 * @param string $action
317 function _financialacls_getRequiredPermission(int $financialTypeID, string $action): string {
318 $financialType = CRM_Core_PseudoConstant
::getName('CRM_Contribute_DAO_Contribution', 'financial_type_id', $financialTypeID);
322 'delete' => 'delete',
324 return $actionMap[$action] . ' contributions of type ' . $financialType;
328 * Remove unpermitted financial types from field Options in search context.
330 * Search context is described as
331 * 'search' => "search: searchable options are returned; labels are translated.",
332 * So this is appropriate to removing the options from search screens.
334 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_fieldOptions
336 * @param string $entity
337 * @param string $field
338 * @param array $options
339 * @param array $params
341 function financialacls_civicrm_fieldOptions($entity, $field, &$options, $params) {
342 if (!financialacls_is_acl_limiting_enabled()) {
345 if (in_array($entity, ['Contribution', 'ContributionRecur'], TRUE) && $field === 'financial_type_id' && $params['context'] === 'search') {
346 $action = CRM_Core_Action
::VIEW
;
347 // At this stage we are only considering the view action. Code from
348 // CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes().
350 CRM_Core_Action
::VIEW
=> 'view',
351 CRM_Core_Action
::UPDATE
=> 'edit',
352 CRM_Core_Action
::ADD
=> 'add',
353 CRM_Core_Action
::DELETE
=> 'delete',
355 $cacheKey = 'available_types_' . $action;
356 if (!isset(\Civi
::$statics['CRM_Financial_BAO_FinancialType'][$cacheKey])) {
357 foreach ($options as $finTypeId => $type) {
358 if (!CRM_Core_Permission
::check($actions[$action] . ' contributions of type ' . $type)) {
359 unset($options[$finTypeId]);
362 \Civi
::$statics['CRM_Financial_BAO_FinancialType'][$cacheKey] = $options;
364 $options = \Civi
::$statics['CRM_Financial_BAO_FinancialType'][$cacheKey];
369 * Is financial acl limiting enabled.
371 * Once this extension is detangled enough to be optional this will go
372 * and the status of the extension rather than the setting will dictate.
376 function financialacls_is_acl_limiting_enabled(): bool {
377 return (bool) Civi
::settings()->get('acl_financial_type');
381 * Clear the statics cache when the setting is enabled or disabled.
383 * Note the setting will eventually disappear in favour of whether
384 * the extension is enabled or disabled.
386 function financialacls_toggle() {
387 unset(\Civi
::$statics['CRM_Financial_BAO_FinancialType']);
390 // --- Functions below this ship commented out. Uncomment as required. ---
393 * Implements hook_civicrm_preProcess().
395 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_preProcess
397 //function financialacls_civicrm_preProcess($formName, &$form) {
402 * Implements hook_civicrm_navigationMenu().
404 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_navigationMenu
406 //function financialacls_civicrm_navigationMenu(&$menu) {
407 // _financialacls_civix_insert_navigation_menu($menu, 'Mailings', array(
408 // 'label' => E::ts('New subliminal message'),
409 // 'name' => 'mailing_subliminal_message',
410 // 'url' => 'civicrm/mailing/subliminal',
411 // 'permission' => 'access CiviMail',
412 // 'operator' => 'OR',
415 // _financialacls_civix_navigationMenu($menu);