Attempt to get rid of pasing by reference and change variable as needed
[civicrm-core.git] / CRM / Financial / BAO / FinancialType.php
CommitLineData
6a488035 1<?php
6a488035
TO
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
0f03f337 6 | Copyright CiviCRM LLC (c) 2004-2017 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
006389de 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
0f03f337 31 * @copyright CiviCRM LLC (c) 2004-2017
6a488035 32 */
6a488035
TO
33class CRM_Financial_BAO_FinancialType extends CRM_Financial_DAO_FinancialType {
34
35 /**
fe482240 36 * Static holder for the default LT.
6a488035 37 */
045f52a3 38 static $_defaultContributionType = NULL;
7f2b2c0d 39 /**
58c3bf5f 40 * Static cache holder of available financial types for this session
7f2b2c0d 41 */
58c3bf5f 42 static $_availableFinancialTypes = array();
5c4bbd48
PN
43 /**
44 * Static cache holder of status of ACL-FT enabled/disabled for this session
45 */
46 static $_statusACLFt = array();
6a488035
TO
47
48 /**
fe482240 49 * Class constructor.
6a488035 50 */
045f52a3 51 public function __construct() {
481a74f4 52 parent::__construct();
6a488035
TO
53 }
54
55 /**
fe482240 56 * Fetch object based on array of properties.
6a488035 57 *
ed5dd492
TO
58 * @param array $params
59 * (reference ) an assoc array of name/value pairs.
60 * @param array $defaults
61 * (reference ) an assoc array to hold the flattened values.
6a488035 62 *
16b10e64 63 * @return CRM_Contribute_BAO_ContributionType
6a488035 64 */
045f52a3 65 public static function retrieve(&$params, &$defaults) {
481a74f4
TO
66 $financialType = new CRM_Financial_DAO_FinancialType();
67 $financialType->copyValues($params);
045f52a3 68 if ($financialType->find(TRUE)) {
481a74f4 69 CRM_Core_DAO::storeValues($financialType, $defaults);
6a488035
TO
70 return $financialType;
71 }
045f52a3 72 return NULL;
6a488035
TO
73 }
74
75 /**
fe482240 76 * Update the is_active flag in the db.
6a488035 77 *
ed5dd492
TO
78 * @param int $id
79 * Id of the database record.
80 * @param bool $is_active
81 * Value we want to set the is_active field.
6a488035 82 *
a6c01b45 83 * @return Object
b44e3f84 84 * DAO object on success, null otherwise
6a488035 85 */
045f52a3 86 public static function setIsActive($id, $is_active) {
481a74f4 87 return CRM_Core_DAO::setFieldValue('CRM_Financial_DAO_FinancialType', $id, 'is_active', $is_active);
6a488035
TO
88 }
89
90 /**
fe482240 91 * Add the financial types.
6a488035 92 *
ed5dd492
TO
93 * @param array $params
94 * Reference array contains the values submitted by the form.
95 * @param array $ids
96 * Reference array contains the id.
6a488035 97 *
6a488035
TO
98 * @return object
99 */
00be9182 100 public static function add(&$params, &$ids = array()) {
22e263ad 101 if (empty($params['id'])) {
045f52a3
TO
102 $params['is_active'] = CRM_Utils_Array::value('is_active', $params, FALSE);
103 $params['is_deductible'] = CRM_Utils_Array::value('is_deductible', $params, FALSE);
104 $params['is_reserved'] = CRM_Utils_Array::value('is_reserved', $params, FALSE);
bc2bc079 105 }
6a488035
TO
106
107 // action is taken depending upon the mode
ddaa8ef1
PN
108 $financialType = new CRM_Financial_DAO_FinancialType();
109 $financialType->copyValues($params);
a7488080 110 if (!empty($ids['financialType'])) {
6a488035 111 $financialType->id = CRM_Utils_Array::value('financialType', $ids);
7fc5cde0
E
112 if (self::isACLFinancialTypeStatus()) {
113 $prevName = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', $financialType->id, 'name');
114 if ($prevName != $params['name']) {
16118599
E
115 CRM_Core_Session::setStatus(ts("Changing the name of a Financial Type will result in losing the current permissions associated with that Financial Type.
116 Before making this change you should likely note the existing permissions at Administer > Users and Permissions > Permissions (Access Control),
117 then clicking the Access Control link for your Content Management System, then noting down the permissions for 'CiviCRM: {financial type name} view', etc.
7fc5cde0
E
118 Then after making the change of name, reset the permissions to the way they were."), ts('Warning'), 'warning');
119 }
120 }
6a488035 121 }
ddaa8ef1
PN
122 $financialType->save();
123 // CRM-12470
bc2bc079 124 if (empty($ids['financialType']) && empty($params['id'])) {
ddaa8ef1
PN
125 $titles = CRM_Financial_BAO_FinancialTypeAccount::createDefaultFinancialAccounts($financialType);
126 $financialType->titles = $titles;
127 }
6a488035
TO
128 return $financialType;
129 }
130
131 /**
fe482240 132 * Delete financial Types.
6a488035 133 *
c490a46a 134 * @param int $financialTypeId
77b97be7
EM
135 *
136 * @return array|bool
6a488035 137 */
00be9182 138 public static function del($financialTypeId) {
481a74f4 139 $financialType = new CRM_Financial_DAO_FinancialType();
71e5aa5c 140 $financialType->id = $financialTypeId;
045f52a3 141 $financialType->find(TRUE);
cf1d2db7
PN
142 // tables to ingore checks for financial_type_id
143 $ignoreTables = array('CRM_Financial_DAO_EntityFinancialAccount');
8ef12e64 144
cded2ebf 145 // TODO: if (!$financialType->find(true)) {
6a488035 146
71e5aa5c
ARW
147 // ensure that we have no objects that have an FK to this financial type id TODO: that cannot be null
148 $occurrences = $financialType->findReferences();
149 if ($occurrences) {
150 $tables = array();
b44e3f84
DS
151 foreach ($occurrences as $occurrence) {
152 $className = get_class($occurrence);
3611044f 153 if (!in_array($className, $tables) && !in_array($className, $ignoreTables)) {
045f52a3 154 $tables[] = $className;
cf1d2db7 155 }
71e5aa5c 156 }
cf1d2db7
PN
157 if (!empty($tables)) {
158 $message = ts('The following tables have an entry for this financial type: %1', array('%1' => implode(', ', $tables)));
6a488035 159
cf1d2db7
PN
160 $errors = array();
161 $errors['is_error'] = 1;
162 $errors['error_message'] = $message;
163 return $errors;
164 }
6a488035
TO
165 }
166
cded2ebf 167 // delete from financial Type table
6a488035
TO
168 $financialType->delete();
169
481a74f4 170 $entityFinancialType = new CRM_Financial_DAO_EntityFinancialAccount();
6a488035
TO
171 $entityFinancialType->entity_id = $financialTypeId;
172 $entityFinancialType->entity_table = 'civicrm_financial_type';
71e5aa5c 173 $entityFinancialType->delete();
6a488035
TO
174 return FALSE;
175 }
8ef12e64 176
6a488035 177 /**
fe482240 178 * fetch financial type having relationship as Income Account is.
6a488035
TO
179 *
180 *
a6c01b45
CW
181 * @return array
182 * all financial type with income account is relationship
6a488035 183 */
00be9182 184 public static function getIncomeFinancialType() {
6a488035
TO
185 // Financial Type
186 $financialType = CRM_Contribute_PseudoConstant::financialType();
187 $revenueFinancialType = array();
f743a6eb 188 $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Income Account is' "));
8ef12e64 189 CRM_Core_PseudoConstant::populate(
6a488035
TO
190 $revenueFinancialType,
191 'CRM_Financial_DAO_EntityFinancialAccount',
045f52a3 192 $all = TRUE,
8ef12e64 193 $retrieve = 'entity_id',
045f52a3 194 $filter = NULL,
8ef12e64 195 "account_relationship = $relationTypeId AND entity_table = 'civicrm_financial_type' "
6a488035 196 );
8ef12e64 197
6a488035 198 foreach ($financialType as $key => $financialTypeName) {
8173dae3 199 if (!in_array($key, $revenueFinancialType)
4323dc6c
PN
200 || (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus()
201 && !CRM_Core_Permission::check('add contributions of type ' . $financialTypeName))
202 ) {
6a488035 203 unset($financialType[$key]);
a8b59c2c 204 }
6a488035
TO
205 }
206 return $financialType;
207 }
96025800 208
4aed5ac0 209 /**
ad37ac8e 210 * Add permissions for financial types.
4aed5ac0 211 *
8173dae3 212 * @param array $permissions
ad37ac8e 213 * @param array $descriptions
214 *
215 * @return bool
4aed5ac0 216 */
cb2f7dd1 217 public static function permissionedFinancialTypes(&$permissions, $descriptions) {
2435064f 218 if (!self::isACLFinancialTypeStatus()) {
92420262 219 return FALSE;
2435064f 220 }
4aed5ac0
E
221 $financialTypes = CRM_Contribute_PseudoConstant::financialType();
222 $prefix = ts('CiviCRM') . ': ';
cb2f7dd1 223 $actions = array('add', 'view', 'edit', 'delete');
4aed5ac0 224 foreach ($financialTypes as $id => $type) {
cb2f7dd1
PN
225 foreach ($actions as $action) {
226 if ($descriptions) {
227 $permissions[$action . ' contributions of type ' . $type] = array(
228 $prefix . ts($action . ' contributions of type ') . $type,
229 ts(ucfirst($action) . ' contributions of type ') . $type,
230 );
231 }
232 else {
233 $permissions[$action . ' contributions of type ' . $type] = $prefix . ts($action . ' contributions of type ') . $type;
234 }
235 }
236 }
237 if (!$descriptions) {
238 $permissions['administer CiviCRM Financial Types'] = $prefix . ts('administer CiviCRM Financial Types');
239 }
240 else {
241 $permissions['administer CiviCRM Financial Types'] = array(
242 $prefix . ts('administer CiviCRM Financial Types'),
243 ts('Administer access to Financial Types'),
92420262 244 );
4aed5ac0 245 }
4aed5ac0 246 }
bb08e888 247
d73f286e
SL
248 /**
249 * CRM-21026
250 * Wrapper aroung getAvaliableFinancialTypes to get all including disabled FinancialTypes
251 * @param array $financialTypes
d51d109d 252 * an array of financial types
d73f286e
SL
253 * @param int|string $action
254 * the type of action, can be add, view, edit, delete
255 * @param bool $resetCache
256 * load values from static cache
257 *
258 * @return array
259 */
d51d109d 260 public static function getAllAvailableFinancialTypes($financialTypes = NULL, $action = CRM_Core_Action::VIEW, $resetCache = FALSE) {
d73f286e
SL
261 // Flush pseudoconstant cache
262 CRM_Contribute_PseudoConstant::flush('financialType');
d51d109d
SL
263 $fTypes = self::getAvailableFinancialTypes($financialTypes, $action, $resetCache, TRUE);
264 return $fTypes;
d73f286e
SL
265 }
266
267 /**
268 * CRM-21026
269 * Wrapper aroung getAvaliableFinancialTypes to get all FinancialTypes Excluding Disabled ones.
270 * @param array $financialTypes
d51d109d 271 * an array of financial types
d73f286e
SL
272 * @param int|string $action
273 * the type of action, can be add, view, edit, delete
274 * @param bool $resetCache
275 * load values from static cache
276 *
277 * @return array
278 */
d51d109d
SL
279 public static function getAllEnabledAvailableFinancialTypes($financialTypes = NULL, $action = CRM_Core_Action::VIEW, $resetCache = FALSE) {
280 $fTypes = self::getAvailableFinancialTypes($financialTypes, $action, $resetCache);
281 return $fTypes;
d73f286e
SL
282 }
283
85b3d95d
E
284 /**
285 * Get available Financial Types.
286 *
287 * @param array $financialTypes
288 * (reference ) an array of financial types
ad37ac8e 289 * @param int|string $action
85b3d95d
E
290 * the type of action, can be add, view, edit, delete
291 * @param bool $resetCache
292 * load values from static cache
d73f286e
SL
293 * @param bool $includeDisabled
294 * Whether we should load in disabled FinancialTypes or Not
85b3d95d
E
295 *
296 * @return array
297 */
d73f286e 298 public static function getAvailableFinancialTypes(&$financialTypes = NULL, $action = CRM_Core_Action::VIEW, $resetCache = FALSE, $includeDisabled = FALSE) {
84e489b7 299 if (empty($financialTypes)) {
d73f286e 300 $financialTypes = CRM_Contribute_PseudoConstant::financialType(NULL, $includeDisabled);
84e489b7 301 }
2435064f
PN
302 if (!self::isACLFinancialTypeStatus()) {
303 return $financialTypes;
dec56960 304 }
573fd305
PN
305 $actions = array(
306 CRM_Core_Action::VIEW => 'view',
307 CRM_Core_Action::UPDATE => 'edit',
308 CRM_Core_Action::ADD => 'add',
309 CRM_Core_Action::DELETE => 'delete',
310 );
58c3bf5f
PN
311 // check cached value
312 if (CRM_Utils_Array::value($action, self::$_availableFinancialTypes) && !$resetCache) {
313 $financialTypes = self::$_availableFinancialTypes[$action];
314 return self::$_availableFinancialTypes[$action];
2435064f 315 }
bb08e888 316 foreach ($financialTypes as $finTypeId => $type) {
573fd305 317 if (!CRM_Core_Permission::check($actions[$action] . ' contributions of type ' . $type)) {
bb08e888
E
318 unset($financialTypes[$finTypeId]);
319 }
320 }
58c3bf5f 321 self::$_availableFinancialTypes[$action] = $financialTypes;
803e39be 322 return $financialTypes;
bb08e888 323 }
dec56960 324
85b3d95d
E
325 /**
326 * Get available Membership Types.
327 *
328 * @param array $membershipTypes
329 * (reference ) an array of membership types
ad37ac8e 330 * @param int|string $action
85b3d95d
E
331 * the type of action, can be add, view, edit, delete
332 *
333 * @return array
334 */
573fd305 335 public static function getAvailableMembershipTypes(&$membershipTypes = NULL, $action = CRM_Core_Action::VIEW) {
27e7373d
E
336 if (empty($membershipTypes)) {
337 $membershipTypes = CRM_Member_PseudoConstant::membershipType();
338 }
2435064f
PN
339 if (!self::isACLFinancialTypeStatus()) {
340 return $membershipTypes;
341 }
573fd305
PN
342 $actions = array(
343 CRM_Core_Action::VIEW => 'view',
344 CRM_Core_Action::UPDATE => 'edit',
345 CRM_Core_Action::ADD => 'add',
346 CRM_Core_Action::DELETE => 'delete',
347 );
27e7373d
E
348 foreach ($membershipTypes as $memTypeId => $type) {
349 $finTypeId = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $memTypeId, 'financial_type_id');
350 $finType = CRM_Contribute_PseudoConstant::financialType($finTypeId);
573fd305 351 if (!CRM_Core_Permission::check($actions[$action] . ' contributions of type ' . $finType)) {
27e7373d
E
352 unset($membershipTypes[$memTypeId]);
353 }
354 }
355 return $membershipTypes;
356 }
81318f84 357
85b3d95d
E
358 /**
359 * Function to build a permissioned sql where clause based on available financial types.
360 *
4a2b8550 361 * @param array $whereClauses
85b3d95d
E
362 * (reference ) an array of clauses
363 * @param string $component
364 * the type of component
365 * @param string $alias
366 * the alias to use
367 *
368 */
1f76c4cd 369 public static function buildPermissionedClause(&$whereClauses, $component = NULL, $alias = NULL) {
2435064f
PN
370 if (!self::isACLFinancialTypeStatus()) {
371 return FALSE;
372 }
be274d8a 373 if (is_array($whereClauses)) {
d51d109d 374 $types = self::getAllEnabledAvailableFinancialTypes();
f71679cf 375 if (empty($types)) {
8173dae3 376 $whereClauses[] = ' ' . $alias . '.financial_type_id IN (0)';
f71679cf
E
377 }
378 else {
a8b59c2c 379 $whereClauses[] = ' ' . $alias . '.financial_type_id IN (' . implode(',', array_keys($types)) . ')';
f71679cf 380 }
be274d8a
E
381 }
382 else {
383 if ($component == 'contribution') {
d1bb399a 384 self::getAvailableFinancialTypes($types);
be274d8a
E
385 $column = "financial_type_id";
386 }
387 if ($component == 'membership') {
761b9c8e 388 self::getAvailableMembershipTypes($types, CRM_Core_Action::VIEW);
be274d8a 389 $column = "membership_type_id";
25cc088b 390 }
761b9c8e 391 if (!empty($whereClauses)) {
f25c0c04 392 $whereClauses .= ' AND ';
761b9c8e 393 }
25cc088b 394 if (empty($types)) {
761b9c8e 395 $whereClauses .= " civicrm_{$component}.{$column} IN (0)";
25cc088b 396 return;
be274d8a 397 }
761b9c8e 398 $whereClauses .= " civicrm_{$component}.{$column} IN (" . implode(',', array_keys($types)) . ")";
81318f84 399 }
81318f84 400 }
59ccc8cd 401
85b3d95d
E
402 /**
403 * Function to check if lineitems present in a contribution have permissioned FTs.
404 *
405 * @param int $id
406 * contribution id
407 * @param string $op
408 * the mode of operation, can be add, view, edit, delete
409 * @param bool $force
410 *
dbb0d30b 411 * @return bool
85b3d95d 412 */
59ccc8cd 413 public static function checkPermissionedLineItems($id, $op, $force = TRUE) {
895d596d
E
414 if (!self::isACLFinancialTypeStatus()) {
415 return TRUE;
416 }
59ccc8cd 417 $lineItems = CRM_Price_BAO_LineItem::getLineItemsByContributionID($id);
b0c2be34 418 $flag = FALSE;
8173dae3 419 foreach ($lineItems as $items) {
59ccc8cd
E
420 if (!CRM_Core_Permission::check($op . ' contributions of type ' . CRM_Contribute_PseudoConstant::financialType($items['financial_type_id']))) {
421 if ($force) {
422 CRM_Core_Error::fatal(ts('You do not have permission to access this page.'));
423 break;
424 }
b0c2be34
E
425 $flag = FALSE;
426 break;
59ccc8cd
E
427 }
428 else {
b0c2be34 429 $flag = TRUE;
59ccc8cd
E
430 }
431 }
b0c2be34 432 return $flag;
59ccc8cd 433 }
85b3d95d 434
2435064f 435 /**
23dba589
SL
436 * Check if the logged in user has permission to edit the given financial type.
437 *
438 * This is called when determining if they can edit things like option values
439 * in price sets. At the moment it is not possible to change an option value from
440 * a type you do not have permission to to a type that you do.
441 *
442 * @todo it is currently not possible to edit disabled types if you have ACLs on.
443 * Do ACLs still apply once disabled? That question should be resolved if tackling
444 * that gap.
445 *
446 * @param int $financialTypeID
447 *
448 * @return bool
449 */
450 public static function checkPermissionToEditFinancialType($financialTypeID) {
451 if (!self::isACLFinancialTypeStatus()) {
452 return TRUE;
453 }
454 // @todo consider adding back in disabled types here.
455 CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes($financialTypes, CRM_Core_Action::UPDATE);
456 return isset($financialTypes[$financialTypeID]);
457 }
458
459 /**
460 * Check if FT-ACL is turned on or off.
461 *
462 * @todo rename this function e.g isFinancialTypeACLsEnabled.
2435064f 463 *
8173dae3 464 * @return bool
2435064f
PN
465 */
466 public static function isACLFinancialTypeStatus() {
5c4bbd48
PN
467 if (array_key_exists('acl_financial_type', self::$_statusACLFt)) {
468 return self::$_statusACLFt['acl_financial_type'];
469 }
aaffa79f 470 $contributeSettings = Civi::settings()->get('contribution_invoice_settings');
5c4bbd48 471 self::$_statusACLFt['acl_financial_type'] = FALSE;
2435064f 472 if (CRM_Utils_Array::value('acl_financial_type', $contributeSettings)) {
5c4bbd48 473 self::$_statusACLFt['acl_financial_type'] = TRUE;
2435064f 474 }
5c4bbd48 475 return self::$_statusACLFt['acl_financial_type'];
2435064f 476 }
a8b59c2c 477
6a488035 478}