Merge pull request #18460 from eileenmcnaughton/comment
[civicrm-core.git] / CRM / Financial / BAO / FinancialItem.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_FinancialItem extends CRM_Financial_DAO_FinancialItem {
18
19 /**
20 * Class constructor.
21 */
22 public function __construct() {
23 parent::__construct();
24 }
25
26 /**
27 * Fetch object based on array of properties.
28 *
29 * @param array $params
30 * (reference ) an assoc array of name/value pairs.
31 * @param array $defaults
32 * (reference ) an assoc array to hold the flattened values.
33 *
34 * @return CRM_Financial_DAO_FinancialItem
35 */
36 public static function retrieve(&$params, &$defaults) {
37 $financialItem = new CRM_Financial_DAO_FinancialItem();
38 $financialItem->copyValues($params);
39 if ($financialItem->find(TRUE)) {
40 CRM_Core_DAO::storeValues($financialItem, $defaults);
41 return $financialItem;
42 }
43 return NULL;
44 }
45
46 /**
47 * Add the financial items and financial trxn.
48 *
49 * @param object $lineItem
50 * Line item object.
51 * @param object $contribution
52 * Contribution object.
53 * @param bool $taxTrxnID
54 *
55 * @param int $trxnId
56 *
57 * @return CRM_Financial_DAO_FinancialItem
58 */
59 public static function add($lineItem, $contribution, $taxTrxnID = FALSE, $trxnId = NULL) {
60 $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
61 $financialItemStatus = CRM_Core_PseudoConstant::get('CRM_Financial_DAO_FinancialItem', 'status_id');
62 $itemStatus = NULL;
63 if ($contribution->contribution_status_id == array_search('Completed', $contributionStatuses)
64 || $contribution->contribution_status_id == array_search('Pending refund', $contributionStatuses)
65 ) {
66 $itemStatus = array_search('Paid', $financialItemStatus);
67 }
68 elseif ($contribution->contribution_status_id == array_search('Pending', $contributionStatuses)
69 || $contribution->contribution_status_id == array_search('In Progress', $contributionStatuses)
70 ) {
71 $itemStatus = array_search('Unpaid', $financialItemStatus);
72 }
73 elseif ($contribution->contribution_status_id == array_search('Partially paid', $contributionStatuses)) {
74 $itemStatus = array_search('Partially paid', $financialItemStatus);
75 }
76 $params = [
77 'transaction_date' => $contribution->receive_date,
78 'contact_id' => $contribution->contact_id,
79 'amount' => $lineItem->line_total,
80 'currency' => $contribution->currency,
81 'entity_table' => 'civicrm_line_item',
82 'entity_id' => $lineItem->id,
83 'description' => ($lineItem->qty != 1 ? $lineItem->qty . ' of ' : '') . $lineItem->label,
84 'status_id' => $itemStatus,
85 ];
86
87 if ($taxTrxnID) {
88 $params['amount'] = $lineItem->tax_amount;
89 $params['description'] = Civi::settings()->get('tax_term');
90 $accountRelName = 'Sales Tax Account is';
91 }
92 else {
93 $accountRelName = 'Income Account is';
94 if (property_exists($contribution, 'revenue_recognition_date') && !CRM_Utils_System::isNull($contribution->revenue_recognition_date)) {
95 $accountRelName = 'Deferred Revenue Account is';
96 }
97 }
98 if ($lineItem->financial_type_id) {
99 $params['financial_account_id'] = CRM_Financial_BAO_FinancialAccount::getFinancialAccountForFinancialTypeByRelationship(
100 $lineItem->financial_type_id,
101 $accountRelName
102 );
103 }
104 if (empty($trxnId)) {
105 $trxnId['id'] = CRM_Contribute_BAO_Contribution::$_trxnIDs;
106 if (empty($trxnId['id'])) {
107 $trxn = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contribution->id, 'ASC', TRUE);
108 $trxnId['id'] = $trxn['financialTrxnId'];
109 }
110 }
111 $financialItem = self::create($params, NULL, $trxnId);
112 return $financialItem;
113 }
114
115 /**
116 * Create the financial Items and financial entity trxn.
117 *
118 * @param array $params
119 * Associated array to create financial items.
120 * @param array $ids
121 * Financial item ids.
122 * @param array $trxnIds
123 * Financial item ids.
124 *
125 * @return CRM_Financial_DAO_FinancialItem
126 */
127 public static function create(&$params, $ids = NULL, $trxnIds = NULL) {
128 $financialItem = new CRM_Financial_DAO_FinancialItem();
129
130 if (!empty($ids['id'])) {
131 CRM_Utils_Hook::pre('edit', 'FinancialItem', $ids['id'], $params);
132 }
133 else {
134 CRM_Utils_Hook::pre('create', 'FinancialItem', NULL, $params);
135 }
136
137 $financialItem->copyValues($params);
138 if (!empty($ids['id'])) {
139 $financialItem->id = $ids['id'];
140 }
141
142 $financialItem->save();
143 $financialtrxnIDS = $trxnIds['id'] ?? NULL;
144 if (!empty($financialtrxnIDS)) {
145 if (!is_array($financialtrxnIDS)) {
146 $financialtrxnIDS = [$financialtrxnIDS];
147 }
148 foreach ($financialtrxnIDS as $tID) {
149 $entity_financial_trxn_params = [
150 'entity_table' => "civicrm_financial_item",
151 'entity_id' => $financialItem->id,
152 'financial_trxn_id' => $tID,
153 'amount' => $params['amount'],
154 ];
155 if (!empty($ids['entityFinancialTrxnId'])) {
156 $entity_financial_trxn_params['id'] = $ids['entityFinancialTrxnId'];
157 }
158 self::createEntityTrxn($entity_financial_trxn_params);
159 }
160 }
161 if (!empty($ids['id'])) {
162 CRM_Utils_Hook::post('edit', 'FinancialItem', $financialItem->id, $financialItem);
163 }
164 else {
165 CRM_Utils_Hook::post('create', 'FinancialItem', $financialItem->id, $financialItem);
166 }
167 return $financialItem;
168 }
169
170 /**
171 * Takes an associative array and creates a entity financial transaction object.
172 *
173 * @param array $params
174 * an assoc array of name/value pairs.
175 *
176 * @return CRM_Financial_DAO_EntityFinancialTrxn
177 */
178 public static function createEntityTrxn($params) {
179 $entity_trxn = new CRM_Financial_DAO_EntityFinancialTrxn();
180 $entity_trxn->copyValues($params);
181 $entity_trxn->save();
182 return $entity_trxn;
183 }
184
185 /**
186 * Retrive entity financial trxn details.
187 *
188 * @param array $params
189 * an assoc array of name/value pairs.
190 * @param bool $maxId
191 * To retrieve max id.
192 *
193 * @return array
194 */
195 public static function retrieveEntityFinancialTrxn($params, $maxId = FALSE) {
196 $financialItem = new CRM_Financial_DAO_EntityFinancialTrxn();
197 $financialItem->copyValues($params);
198 // retrieve last entry from civicrm_entity_financial_trxn
199 if ($maxId) {
200 $financialItem->orderBy('id DESC');
201 $financialItem->limit(1);
202 }
203 $financialItem->find();
204 while ($financialItem->fetch()) {
205 $financialItems[$financialItem->id] = [
206 'id' => $financialItem->id,
207 'entity_table' => $financialItem->entity_table,
208 'entity_id' => $financialItem->entity_id,
209 'financial_trxn_id' => $financialItem->financial_trxn_id,
210 'amount' => $financialItem->amount,
211 ];
212 }
213 if (!empty($financialItems)) {
214 return $financialItems;
215 }
216 else {
217 return NULL;
218 }
219 }
220
221 /**
222 * Check if contact is present in financial_item table.
223 *
224 * @see https://issues.civicrm.org/jira/browse/CRM-12929
225 *
226 * @param array $contactIds
227 * An array contact id's.
228 *
229 * @param array $error
230 * Error to display.
231 *
232 * @return array|bool
233 */
234 public static function checkContactPresent($contactIds, &$error) {
235 if (empty($contactIds)) {
236 return FALSE;
237 }
238
239 $allowPermDelete = Civi::settings()->get('allowPermDeleteFinancial');
240
241 if (!$allowPermDelete) {
242 $sql = 'SELECT DISTINCT(cc.id), cc.display_name FROM civicrm_contact cc
243 INNER JOIN civicrm_contribution con ON con.contact_id = cc.id
244 WHERE cc.id IN (' . implode(',', $contactIds) . ') AND con.is_test = 0';
245 $dao = CRM_Core_DAO::executeQuery($sql);
246 if ($dao->N) {
247 while ($dao->fetch()) {
248 $url = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid=$dao->id");
249 $not_deleted[$dao->id] = "<a href='$url'>$dao->display_name</a>";
250 }
251
252 $errorStatus = '';
253 if (is_array($error)) {
254 $errorStatus = '<ul><li>' . implode('</li><li>', $not_deleted) . '</li></ul>';
255 }
256
257 $error['_qf_default'] = $errorStatus . ts('This contact(s) can not be permanently deleted because the contact record is linked to one or more live financial transactions. Deleting this contact would result in the loss of financial data.');
258 return $error;
259 }
260 }
261 return FALSE;
262 }
263
264 /**
265 * Get most relevant previous financial item relating to the line item.
266 *
267 * This function specifically excludes sales tax.
268 *
269 * @param int $entityId
270 *
271 * @return array
272 */
273 public static function getPreviousFinancialItem($entityId) {
274 $params = [
275 'entity_id' => $entityId,
276 'entity_table' => 'civicrm_line_item',
277 'options' => ['limit' => 1, 'sort' => 'id DESC'],
278 ];
279 $salesTaxFinancialAccounts = civicrm_api3('FinancialAccount', 'get', ['is_tax' => 1]);
280 if ($salesTaxFinancialAccounts['count']) {
281 $params['financial_account_id'] = ['NOT IN' => array_keys($salesTaxFinancialAccounts['values'])];
282 }
283 return civicrm_api3('FinancialItem', 'getsingle', $params);
284 }
285
286 }