Merge pull request #21865 from colemanw/SearchKitTags
[civicrm-core.git] / CRM / Financial / BAO / FinancialTypeAccount.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17 class CRM_Financial_BAO_FinancialTypeAccount extends CRM_Financial_DAO_EntityFinancialAccount {
18
19 /**
20 * Fetch object based on array of properties.
21 *
22 * @param array $params
23 * (reference ) an assoc array of name/value pairs.
24 * @param array $defaults
25 * (reference ) an assoc array to hold the flattened values.
26 *
27 * @param array $allValues
28 *
29 * @return CRM_Contribute_BAO_ContributionType
30 */
31 public static function retrieve(&$params, &$defaults = [], &$allValues = []) {
32 $financialTypeAccount = new CRM_Financial_DAO_EntityFinancialAccount();
33 $financialTypeAccount->copyValues($params);
34 $financialTypeAccount->find();
35 while ($financialTypeAccount->fetch()) {
36 CRM_Core_DAO::storeValues($financialTypeAccount, $defaults);
37 $allValues[] = $defaults;
38 }
39 return $defaults;
40 }
41
42 /**
43 * Add the financial types.
44 *
45 * @param array $params
46 * Reference array contains the values submitted by the form.
47 * @param array $ids
48 * Reference array contains one possible value
49 * - entityFinancialAccount.
50 *
51 * @return CRM_Financial_DAO_EntityFinancialAccount
52 *
53 * @throws \CRM_Core_Exception
54 */
55 public static function add(&$params, $ids = NULL) {
56 // action is taken depending upon the mode
57 $financialTypeAccount = new CRM_Financial_DAO_EntityFinancialAccount();
58 if ($params['entity_table'] !== 'civicrm_financial_type') {
59 $financialTypeAccount->entity_id = $params['entity_id'];
60 $financialTypeAccount->entity_table = $params['entity_table'];
61 $financialTypeAccount->find(TRUE);
62 }
63 if (!empty($ids['entityFinancialAccount'])) {
64 $financialTypeAccount->id = $ids['entityFinancialAccount'];
65 $financialTypeAccount->find(TRUE);
66 }
67 $financialTypeAccount->copyValues($params);
68 self::validateRelationship($financialTypeAccount);
69 $financialTypeAccount->save();
70 unset(Civi::$statics['CRM_Core_PseudoConstant']['taxRates']);
71 return $financialTypeAccount;
72 }
73
74 /**
75 * Delete financial Types.
76 *
77 * @param int $financialTypeAccountId
78 * @param int $accountId
79 *
80 * @throws \CRM_Core_Exception
81 */
82 public static function del($financialTypeAccountId, $accountId = NULL) {
83 // check if financial type is present
84 $check = FALSE;
85 $relationValues = CRM_Core_PseudoConstant::get('CRM_Financial_DAO_EntityFinancialAccount', 'account_relationship');
86
87 $financialTypeId = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_EntityFinancialAccount', $financialTypeAccountId, 'entity_id');
88 // check dependencies
89 // FIXME hardcoded list = bad
90 $dependency = [
91 ['Contribute', 'Contribution'],
92 ['Contribute', 'ContributionPage'],
93 ['Member', 'MembershipType'],
94 ['Price', 'PriceFieldValue'],
95 ['Grant', 'Grant'],
96 ['Contribute', 'PremiumsProduct'],
97 ['Contribute', 'Product'],
98 ['Price', 'LineItem'],
99 ];
100
101 foreach ($dependency as $name) {
102 $daoString = 'CRM_' . $name[0] . '_DAO_' . $name[1];
103 if (class_exists($daoString)) {
104 /* @var \CRM_Core_DAO $dao */
105 $dao = new $daoString();
106 $dao->financial_type_id = $financialTypeId;
107 if ($dao->find(TRUE)) {
108 $check = TRUE;
109 break;
110 }
111 }
112 }
113
114 if ($check) {
115 if ($name[1] === 'PremiumsProduct' || $name[1] === 'Product') {
116 CRM_Core_Session::setStatus(ts('You cannot remove an account with a %1 relationship while the Financial Type is used for a Premium.', [1 => $relationValues[$financialTypeAccountId]]));
117 }
118 else {
119 $accountRelationShipId = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_EntityFinancialAccount', $financialTypeAccountId, 'account_relationship');
120 CRM_Core_Session::setStatus(ts('You cannot remove an account with a %1 relationship because it is being referenced by one or more of the following types of records: Contributions, Contribution Pages, or Membership Types. Consider disabling this type instead if you no longer want it used.', [1 => $relationValues[$accountRelationShipId]]), NULL, 'error');
121 }
122 return CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin/financial/financialType/accounts', "reset=1&action=browse&aid={$accountId}"));
123 }
124
125 // delete from financial Type table
126 $financialType = new CRM_Financial_DAO_EntityFinancialAccount();
127 $financialType->id = $financialTypeAccountId;
128 $financialType->find(TRUE);
129 $financialType->delete();
130 CRM_Core_Session::setStatus(ts('Unbalanced transactions may be created if you delete the account of type: %1.', [1 => $relationValues[$financialType->account_relationship]]));
131 }
132
133 /**
134 * Financial Account for payment instrument.
135 *
136 * @param int $paymentInstrumentValue
137 * Payment instrument value.
138 *
139 * @return null|int
140 * @throws \CiviCRM_API3_Exception
141 */
142 public static function getInstrumentFinancialAccount($paymentInstrumentValue) {
143 if (!isset(\Civi::$statics[__CLASS__]['instrument_financial_accounts'][$paymentInstrumentValue])) {
144 $paymentInstrumentID = civicrm_api3('OptionValue', 'getvalue', [
145 'return' => 'id',
146 'value' => $paymentInstrumentValue,
147 'option_group_id' => "payment_instrument",
148 ]);
149 $accounts = civicrm_api3('EntityFinancialAccount', 'get', [
150 'return' => 'financial_account_id',
151 'entity_table' => 'civicrm_option_value',
152 'entity_id' => $paymentInstrumentID,
153 'options' => ['limit' => 1],
154 'sequential' => 1,
155 ])['values'];
156 if (empty($accounts)) {
157 \Civi::$statics[__CLASS__]['instrument_financial_accounts'][$paymentInstrumentValue] = NULL;
158 }
159 else {
160 \Civi::$statics[__CLASS__]['instrument_financial_accounts'][$paymentInstrumentValue] = $accounts[0]['financial_account_id'];
161 }
162 }
163 return \Civi::$statics[__CLASS__]['instrument_financial_accounts'][$paymentInstrumentValue];
164 }
165
166 /**
167 * Create default entity financial accounts
168 * for financial type
169 * @see https://issues.civicrm.org/jira/browse/CRM-12470
170 *
171 * @param $financialType
172 *
173 * @return array
174 */
175 public static function createDefaultFinancialAccounts($financialType) {
176 $titles = [];
177 $financialAccountTypeID = CRM_Core_OptionGroup::values('financial_account_type', FALSE, FALSE, FALSE, NULL, 'name');
178 $accountRelationship = CRM_Core_OptionGroup::values('account_relationship', FALSE, FALSE, FALSE, NULL, 'name');
179
180 $relationships = [
181 array_search('Accounts Receivable Account is', $accountRelationship) => array_search('Asset', $financialAccountTypeID),
182 array_search('Expense Account is', $accountRelationship) => array_search('Expenses', $financialAccountTypeID),
183 array_search('Cost of Sales Account is', $accountRelationship) => array_search('Cost of Sales', $financialAccountTypeID),
184 array_search('Income Account is', $accountRelationship) => array_search('Revenue', $financialAccountTypeID),
185 ];
186
187 $dao = CRM_Core_DAO::executeQuery('SELECT id, financial_account_type_id FROM civicrm_financial_account WHERE name LIKE %1',
188 [1 => [$financialType->name, 'String']]
189 );
190 $dao->fetch();
191 $existingFinancialAccount = [];
192 if (!$dao->N) {
193 $params = [
194 'name' => $financialType->name,
195 'contact_id' => CRM_Core_BAO_Domain::getDomain()->contact_id,
196 'financial_account_type_id' => array_search('Revenue', $financialAccountTypeID),
197 'description' => $financialType->description,
198 'account_type_code' => 'INC',
199 'is_active' => 1,
200 ];
201 $financialAccount = CRM_Financial_BAO_FinancialAccount::add($params);
202 }
203 else {
204 $existingFinancialAccount[$dao->financial_account_type_id] = $dao->id;
205 }
206 $params = [
207 'entity_table' => 'civicrm_financial_type',
208 'entity_id' => $financialType->id,
209 ];
210 foreach ($relationships as $key => $value) {
211 if (!array_key_exists($value, $existingFinancialAccount)) {
212 if ($accountRelationship[$key] == 'Accounts Receivable Account is') {
213 $params['financial_account_id'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialAccount', 'Accounts Receivable', 'id', 'name');
214 if (!empty($params['financial_account_id'])) {
215 $titles[] = 'Accounts Receivable';
216 }
217 else {
218 $query = "SELECT financial_account_id, name FROM civicrm_entity_financial_account
219 LEFT JOIN civicrm_financial_account ON civicrm_financial_account.id = civicrm_entity_financial_account.financial_account_id
220 WHERE account_relationship = {$key} AND entity_table = 'civicrm_financial_type' LIMIT 1";
221 $dao = CRM_Core_DAO::executeQuery($query);
222 $dao->fetch();
223 $params['financial_account_id'] = $dao->financial_account_id;
224 $titles[] = $dao->name;
225 }
226 }
227 elseif ($accountRelationship[$key] == 'Income Account is' && empty($existingFinancialAccount)) {
228 $params['financial_account_id'] = $financialAccount->id;
229 }
230 else {
231 $query = "SELECT id, name FROM civicrm_financial_account WHERE is_default = 1 AND financial_account_type_id = {$value}";
232 $dao = CRM_Core_DAO::executeQuery($query);
233 $dao->fetch();
234 $params['financial_account_id'] = $dao->id;
235 $titles[] = $dao->name;
236 }
237 }
238 else {
239 $params['financial_account_id'] = $existingFinancialAccount[$value];
240 $titles[] = $financialType->name;
241 }
242 $params['account_relationship'] = $key;
243 self::add($params);
244 }
245 if (!empty($existingFinancialAccount)) {
246 $titles = [];
247 }
248 return $titles;
249 }
250
251 /**
252 * Validate account relationship with financial account type
253 *
254 * @param CRM_Financial_DAO_EntityFinancialAccount $financialTypeAccount of CRM_Financial_DAO_EntityFinancialAccount
255 *
256 * @throws CRM_Core_Exception
257 */
258 public static function validateRelationship($financialTypeAccount) {
259 $financialAccountLinks = CRM_Financial_BAO_FinancialAccount::getfinancialAccountRelations();
260 $financialAccountType = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialAccount', $financialTypeAccount->financial_account_id, 'financial_account_type_id');
261 if (CRM_Utils_Array::value($financialTypeAccount->account_relationship, $financialAccountLinks) != $financialAccountType) {
262 $accountRelationships = CRM_Core_PseudoConstant::get('CRM_Financial_DAO_EntityFinancialAccount', 'account_relationship');
263 $params = [
264 1 => $accountRelationships[$financialTypeAccount->account_relationship],
265 ];
266 throw new CRM_Core_Exception(ts("This financial account cannot have '%1' relationship.", $params));
267 }
268 }
269
270 }