Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
fee14197 | 4 | | CiviCRM version 5 | |
6a488035 | 5 | +--------------------------------------------------------------------+ |
6b83d5bd | 6 | | Copyright CiviCRM LLC (c) 2004-2019 | |
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 | +--------------------------------------------------------------------+ | |
d25dd0ee | 26 | */ |
6a488035 TO |
27 | |
28 | /** | |
29 | * | |
30 | * @package CRM | |
6b83d5bd | 31 | * @copyright CiviCRM LLC (c) 2004-2019 |
6a488035 TO |
32 | */ |
33 | ||
34 | /** | |
35 | * Business objects for Line Items generated by monetary transactions | |
36 | */ | |
37 | class CRM_Price_BAO_LineItem extends CRM_Price_DAO_LineItem { | |
38 | ||
39 | /** | |
40 | * Creates a new entry in the database. | |
41 | * | |
414c1420 TO |
42 | * @param array $params |
43 | * (reference) an assoc array of name/value pairs. | |
6a488035 | 44 | * |
8e8d287f | 45 | * @return \CRM_Price_DAO_LineItem |
46 | * | |
47 | * @throws \CiviCRM_API3_Exception | |
48 | * @throws \Exception | |
6a488035 | 49 | */ |
00be9182 | 50 | public static function create(&$params) { |
22fe049d PN |
51 | $id = CRM_Utils_Array::value('id', $params); |
52 | if ($id) { | |
53 | CRM_Utils_Hook::pre('edit', 'LineItem', $id, $params); | |
513e5875 | 54 | $op = CRM_Core_Action::UPDATE; |
22fe049d PN |
55 | } |
56 | else { | |
57 | CRM_Utils_Hook::pre('create', 'LineItem', $params['entity_id'], $params); | |
513e5875 | 58 | $op = CRM_Core_Action::ADD; |
22fe049d | 59 | } |
c206647d | 60 | |
22fe049d PN |
61 | // unset entity table and entity id in $params |
62 | // we never update the entity table and entity id during update mode | |
63 | if ($id) { | |
81e50d63 NG |
64 | $entity_id = CRM_Utils_Array::value('entity_id', $params); |
65 | $entity_table = CRM_Utils_Array::value('entity_table', $params); | |
22fe049d PN |
66 | unset($params['entity_id'], $params['entity_table']); |
67 | } | |
13a16f43 | 68 | else { |
69 | if (!isset($params['unit_price'])) { | |
70 | $params['unit_price'] = 0; | |
71 | } | |
72 | } | |
93b21909 | 73 | if (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus() && CRM_Utils_Array::value('check_permissions', $params)) { |
cfba316e E |
74 | if (empty($params['financial_type_id'])) { |
75 | throw new Exception('Mandatory key(s) missing from params array: financial_type_id'); | |
76 | } | |
513e5875 E |
77 | CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes($types, $op); |
78 | if (!in_array($params['financial_type_id'], array_keys($types))) { | |
f8acc368 | 79 | throw new Exception('You do not have permission to create this line item'); |
513e5875 E |
80 | } |
81 | } | |
421dfaa6 | 82 | |
6a488035 TO |
83 | $lineItemBAO = new CRM_Price_BAO_LineItem(); |
84 | $lineItemBAO->copyValues($params); | |
85 | ||
86 | $return = $lineItemBAO->save(); | |
43c8d1dd | 87 | if ($lineItemBAO->entity_table == 'civicrm_membership' && $lineItemBAO->contribution_id && $lineItemBAO->entity_id) { |
be2fb01f | 88 | $membershipPaymentParams = [ |
43c8d1dd | 89 | 'membership_id' => $lineItemBAO->entity_id, |
90 | 'contribution_id' => $lineItemBAO->contribution_id, | |
be2fb01f | 91 | ]; |
43c8d1dd | 92 | if (!civicrm_api3('MembershipPayment', 'getcount', $membershipPaymentParams)) { |
93 | civicrm_api3('MembershipPayment', 'create', $membershipPaymentParams); | |
94 | } | |
95 | } | |
6a488035 | 96 | |
22fe049d | 97 | if ($id) { |
29f2587b NG |
98 | // CRM-21281: Restore entity reference in case the post hook needs it |
99 | $lineItemBAO->entity_id = $entity_id; | |
100 | $lineItemBAO->entity_table = $entity_table; | |
3ef5b847 | 101 | CRM_Utils_Hook::post('edit', 'LineItem', $id, $lineItemBAO); |
22fe049d PN |
102 | } |
103 | else { | |
3ef5b847 | 104 | CRM_Utils_Hook::post('create', 'LineItem', $lineItemBAO->id, $lineItemBAO); |
22fe049d | 105 | } |
6a488035 TO |
106 | |
107 | return $return; | |
108 | } | |
109 | ||
110 | /** | |
fe482240 EM |
111 | * Retrieve DB object based on input parameters. |
112 | * | |
113 | * It also stores all the retrieved values in the default array. | |
6a488035 | 114 | * |
414c1420 TO |
115 | * @param array $params |
116 | * (reference ) an assoc array of name/value pairs. | |
117 | * @param array $defaults | |
118 | * (reference ) an assoc array to hold the flattened values. | |
6a488035 | 119 | * |
16b10e64 | 120 | * @return CRM_Price_BAO_LineItem |
6a488035 | 121 | */ |
00be9182 | 122 | public static function retrieve(&$params, &$defaults) { |
6a488035 TO |
123 | $lineItem = new CRM_Price_BAO_LineItem(); |
124 | $lineItem->copyValues($params); | |
125 | if ($lineItem->find(TRUE)) { | |
126 | CRM_Core_DAO::storeValues($lineItem, $defaults); | |
127 | return $lineItem; | |
128 | } | |
129 | return NULL; | |
130 | } | |
131 | ||
ac5a0d1c E |
132 | /** |
133 | * Modifies $params array for filtering financial types. | |
134 | * | |
135 | * @param array $params | |
136 | * (reference ) an assoc array of name/value pairs. | |
137 | * | |
138 | */ | |
139 | public static function getAPILineItemParams(&$params) { | |
140 | CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes($types); | |
141 | if ($types && empty($params['financial_type_id'])) { | |
be2fb01f | 142 | $params['financial_type_id'] = ['IN' => array_keys($types)]; |
ac5a0d1c E |
143 | } |
144 | elseif ($types) { | |
145 | if (is_array($params['financial_type_id'])) { | |
146 | $invalidFts = array_diff($params['financial_type_id'], array_keys($types)); | |
147 | } | |
148 | elseif (!in_array($params['financial_type_id'], array_keys($types))) { | |
149 | $invalidFts = $params['financial_type_id']; | |
150 | } | |
151 | if ($invalidFts) { | |
be2fb01f | 152 | $params['financial_type_id'] = ['NOT IN' => $invalidFts]; |
ac5a0d1c E |
153 | } |
154 | } | |
155 | else { | |
156 | $params['financial_type_id'] = 0; | |
157 | } | |
158 | } | |
159 | ||
ffd93213 | 160 | /** |
ae3a9643 | 161 | * @param int $contributionId |
ffd93213 EM |
162 | * |
163 | * @return null|string | |
164 | */ | |
ae3a9643 | 165 | public static function getLineTotal($contributionId) { |
5a18a545 | 166 | $sqlLineItemTotal = "SELECT SUM(li.line_total + COALESCE(li.tax_amount,0)) |
bc2eeabb | 167 | FROM civicrm_line_item li |
ae3a9643 | 168 | WHERE li.contribution_id = %1"; |
be2fb01f | 169 | $params = [1 => [$contributionId, 'Integer']]; |
ae3a9643 | 170 | $lineItemTotal = CRM_Core_DAO::singleValueQuery($sqlLineItemTotal, $params); |
bc2eeabb PJ |
171 | return $lineItemTotal; |
172 | } | |
173 | ||
34a100a7 | 174 | /** |
fe482240 | 175 | * Wrapper for line item retrieval when contribution ID is known. |
100fef9d | 176 | * @param int $contributionID |
34a100a7 EM |
177 | * |
178 | * @return array | |
179 | */ | |
00be9182 | 180 | public static function getLineItemsByContributionID($contributionID) { |
5c26c908 | 181 | return self::getLineItems($contributionID, 'contribution', NULL, TRUE, TRUE); |
34a100a7 EM |
182 | } |
183 | ||
6a488035 TO |
184 | /** |
185 | * Given a participant id/contribution id, | |
186 | * return contribution/fee line items | |
187 | * | |
5a4f6742 CW |
188 | * @param int $entityId |
189 | * participant/contribution id. | |
190 | * @param string $entity | |
191 | * participant/contribution. | |
6a488035 | 192 | * |
77dbdcbc | 193 | * @param bool $isQuick |
dd244018 | 194 | * @param bool $isQtyZero |
0d6f29cd | 195 | * @param bool $relatedEntity |
dd244018 | 196 | * |
111775d3 | 197 | * @param bool $invoice |
a6c01b45 | 198 | * @return array |
16b10e64 | 199 | * Array of line items |
6a488035 | 200 | */ |
77dbdcbc | 201 | public static function getLineItems($entityId, $entity = 'participant', $isQuick = FALSE, $isQtyZero = TRUE, $relatedEntity = FALSE, $invoice = FALSE) { |
34a100a7 | 202 | $whereClause = $fromClause = NULL; |
6a488035 TO |
203 | $selectClause = " |
204 | SELECT li.id, | |
205 | li.label, | |
a7886853 | 206 | li.contribution_id, |
6a488035 TO |
207 | li.qty, |
208 | li.unit_price, | |
209 | li.line_total, | |
34a100a7 EM |
210 | li.entity_table, |
211 | li.entity_id, | |
6a488035 TO |
212 | pf.label as field_title, |
213 | pf.html_type, | |
28b46c26 | 214 | pf.price_set_id, |
6a488035 | 215 | pfv.membership_type_id, |
9c09f5b7 | 216 | pfv.membership_num_terms, |
6a488035 TO |
217 | li.price_field_id, |
218 | li.participant_count, | |
219 | li.price_field_value_id, | |
bf45dbe8 | 220 | li.financial_type_id, |
9849720e | 221 | li.tax_amount, |
6a488035 TO |
222 | pfv.description"; |
223 | ||
0d6f29cd | 224 | $condition = "li.entity_id = %2.id AND li.entity_table = 'civicrm_%2'"; |
225 | if ($relatedEntity) { | |
226 | $condition = "li.contribution_id = %2.id "; | |
227 | } | |
228 | ||
6a488035 TO |
229 | $fromClause = " |
230 | FROM civicrm_%2 as %2 | |
0d6f29cd | 231 | LEFT JOIN civicrm_line_item li ON ({$condition}) |
6a488035 TO |
232 | LEFT JOIN civicrm_price_field_value pfv ON ( pfv.id = li.price_field_value_id ) |
233 | LEFT JOIN civicrm_price_field pf ON (pf.id = li.price_field_id )"; | |
234 | $whereClause = " | |
235 | WHERE %2.id = %1"; | |
236 | ||
25d0c647 WA |
237 | // CRM-16250 get additional participant's fee selection details only for invoice PDF (if any) |
238 | if ($entity == 'participant' && $invoice) { | |
0977cd6e | 239 | $additionalParticipantIDs = CRM_Event_BAO_Participant::getAdditionalParticipantIds($entityId); |
240 | if (!empty($additionalParticipantIDs)) { | |
36165903 | 241 | $whereClause = "WHERE %2.id IN (%1, " . implode(', ', $additionalParticipantIDs) . ")"; |
0977cd6e | 242 | } |
243 | } | |
244 | ||
e68f41a5 DG |
245 | $orderByClause = " ORDER BY pf.weight, pfv.weight"; |
246 | ||
6a488035 TO |
247 | if ($isQuick) { |
248 | $fromClause .= " LEFT JOIN civicrm_price_set cps on cps.id = pf.price_set_id "; | |
249 | $whereClause .= " and cps.is_quick_config = 0"; | |
250 | } | |
d5397f2f PJ |
251 | |
252 | if (!$isQtyZero) { | |
253 | $whereClause .= " and li.qty != 0"; | |
254 | } | |
255 | ||
be2fb01f | 256 | $lineItems = []; |
6a488035 TO |
257 | |
258 | if (!$entityId || !$entity || !$fromClause) { | |
259 | return $lineItems; | |
260 | } | |
261 | ||
be2fb01f CW |
262 | $params = [ |
263 | 1 => [$entityId, 'Integer'], | |
264 | 2 => [$entity, 'Text'], | |
265 | ]; | |
6a488035 | 266 | |
2feea3d1 | 267 | $getTaxDetails = FALSE; |
aaffa79f | 268 | $invoiceSettings = Civi::settings()->get('contribution_invoice_settings'); |
03b412ae | 269 | $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings); |
34a100a7 | 270 | |
e68f41a5 | 271 | $dao = CRM_Core_DAO::executeQuery("$selectClause $fromClause $whereClause $orderByClause", $params); |
6a488035 TO |
272 | while ($dao->fetch()) { |
273 | if (!$dao->id) { | |
274 | continue; | |
275 | } | |
be2fb01f | 276 | $lineItems[$dao->id] = [ |
4dc7af82 | 277 | 'qty' => (float) $dao->qty, |
6a488035 TO |
278 | 'label' => $dao->label, |
279 | 'unit_price' => $dao->unit_price, | |
280 | 'line_total' => $dao->line_total, | |
281 | 'price_field_id' => $dao->price_field_id, | |
282 | 'participant_count' => $dao->participant_count, | |
283 | 'price_field_value_id' => $dao->price_field_value_id, | |
284 | 'field_title' => $dao->field_title, | |
285 | 'html_type' => $dao->html_type, | |
286 | 'description' => $dao->description, | |
77dbdcbc | 287 | 'entity_id' => $dao->entity_id, |
34a100a7 | 288 | 'entity_table' => $dao->entity_table, |
a7886853 | 289 | 'contribution_id' => $dao->contribution_id, |
bf45dbe8 | 290 | 'financial_type_id' => $dao->financial_type_id, |
64525dae | 291 | 'financial_type' => CRM_Core_PseudoConstant::getLabel('CRM_Contribute_BAO_Contribution', 'financial_type_id', $dao->financial_type_id), |
6a488035 | 292 | 'membership_type_id' => $dao->membership_type_id, |
9c09f5b7 | 293 | 'membership_num_terms' => $dao->membership_num_terms, |
9849720e | 294 | 'tax_amount' => $dao->tax_amount, |
28b46c26 | 295 | 'price_set_id' => $dao->price_set_id, |
be2fb01f | 296 | ]; |
4f5911bb K |
297 | $taxRates = CRM_Core_PseudoConstant::getTaxRates(); |
298 | if (isset($lineItems[$dao->id]['financial_type_id']) && array_key_exists($lineItems[$dao->id]['financial_type_id'], $taxRates)) { | |
8684f612 MW |
299 | // Cast to float so trailing zero decimals are removed for display. |
300 | $lineItems[$dao->id]['tax_rate'] = (float) $taxRates[$lineItems[$dao->id]['financial_type_id']]; | |
4f5911bb K |
301 | } |
302 | else { | |
303 | // There is no Tax Rate associated with this Financial Type | |
304 | $lineItems[$dao->id]['tax_rate'] = FALSE; | |
305 | } | |
9849720e | 306 | $lineItems[$dao->id]['subTotal'] = $lineItems[$dao->id]['qty'] * $lineItems[$dao->id]['unit_price']; |
2feea3d1 PB |
307 | if ($lineItems[$dao->id]['tax_amount'] != '') { |
308 | $getTaxDetails = TRUE; | |
309 | } | |
6a488035 | 310 | } |
03b412ae | 311 | if ($invoicing) { |
1c281d1d | 312 | // @todo - this is an inappropriate place to be doing form level assignments. |
03b412ae PB |
313 | $taxTerm = CRM_Utils_Array::value('tax_term', $invoiceSettings); |
314 | $smarty = CRM_Core_Smarty::singleton(); | |
315 | $smarty->assign('taxTerm', $taxTerm); | |
316 | $smarty->assign('getTaxDetails', $getTaxDetails); | |
317 | } | |
6a488035 TO |
318 | return $lineItems; |
319 | } | |
320 | ||
321 | /** | |
322 | * This method will create the lineItem array required for | |
323 | * processAmount method | |
324 | * | |
414c1420 TO |
325 | * @param int $fid |
326 | * Price set field id. | |
327 | * @param array $params | |
328 | * Reference to form values. | |
329 | * @param array $fields | |
1a1a2f4f | 330 | * Array of fields belonging to the price set used for particular event |
414c1420 TO |
331 | * @param array $values |
332 | * Reference to the values array(. | |
16b10e64 | 333 | * this is |
6a488035 | 334 | * lineItem array) |
1a1a2f4f | 335 | * @param string $amount_override |
83644f47 | 336 | * Amount override must be in format 1000.00 - ie no thousand separator & if |
337 | * a decimal point is used it should be a decimal | |
338 | * | |
339 | * @todo - this parameter is only used for partial payments. It's unclear why a partial | |
340 | * payment would change the line item price. | |
6a488035 | 341 | */ |
1a1a2f4f | 342 | public static function format($fid, $params, $fields, &$values, $amount_override = NULL) { |
6a488035 TO |
343 | if (empty($params["price_{$fid}"])) { |
344 | return; | |
345 | } | |
346 | ||
6a488035 TO |
347 | //lets first check in fun parameter, |
348 | //since user might modified w/ hooks. | |
be2fb01f | 349 | $options = []; |
6a488035 TO |
350 | if (array_key_exists('options', $fields)) { |
351 | $options = $fields['options']; | |
352 | } | |
353 | else { | |
9da8dc8c | 354 | CRM_Price_BAO_PriceFieldValue::getValues($fid, $options, 'weight', TRUE); |
6a488035 TO |
355 | } |
356 | $fieldTitle = CRM_Utils_Array::value('label', $fields); | |
357 | if (!$fieldTitle) { | |
9da8dc8c | 358 | $fieldTitle = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', $fid, 'label'); |
6a488035 TO |
359 | } |
360 | ||
361 | foreach ($params["price_{$fid}"] as $oid => $qty) { | |
1a1a2f4f | 362 | $price = $amount_override === NULL ? $options[$oid]['amount'] : $amount_override; |
6a488035 | 363 | |
6a488035 TO |
364 | $participantsPerField = CRM_Utils_Array::value('count', $options[$oid], 0); |
365 | ||
be2fb01f | 366 | $values[$oid] = [ |
6a488035 TO |
367 | 'price_field_id' => $fid, |
368 | 'price_field_value_id' => $oid, | |
369 | 'label' => CRM_Utils_Array::value('label', $options[$oid]), | |
370 | 'field_title' => $fieldTitle, | |
371 | 'description' => CRM_Utils_Array::value('description', $options[$oid]), | |
372 | 'qty' => $qty, | |
373 | 'unit_price' => $price, | |
374 | 'line_total' => $qty * $price, | |
375 | 'participant_count' => $qty * $participantsPerField, | |
376 | 'max_value' => CRM_Utils_Array::value('max_value', $options[$oid]), | |
377 | 'membership_type_id' => CRM_Utils_Array::value('membership_type_id', $options[$oid]), | |
378 | 'membership_num_terms' => CRM_Utils_Array::value('membership_num_terms', $options[$oid]), | |
379 | 'auto_renew' => CRM_Utils_Array::value('auto_renew', $options[$oid]), | |
380 | 'html_type' => $fields['html_type'], | |
bf45dbe8 | 381 | 'financial_type_id' => CRM_Utils_Array::value('financial_type_id', $options[$oid]), |
5a18a545 | 382 | 'tax_amount' => CRM_Utils_Array::value('tax_amount', $options[$oid]), |
5afce5ad | 383 | 'non_deductible_amount' => CRM_Utils_Array::value('non_deductible_amount', $options[$oid]), |
be2fb01f | 384 | ]; |
cdeb4bdf | 385 | |
e03317f1 | 386 | if ($values[$oid]['membership_type_id'] && empty($values[$oid]['auto_renew'])) { |
421dfaa6 | 387 | $values[$oid]['auto_renew'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $values[$oid]['membership_type_id'], 'auto_renew'); |
6a488035 TO |
388 | } |
389 | } | |
390 | } | |
391 | ||
392 | /** | |
393 | * Delete line items for given entity. | |
394 | * | |
395 | * @param int $entityId | |
396 | * @param int $entityTable | |
397 | * | |
77b97be7 | 398 | * @return bool |
6a488035 | 399 | */ |
421dfaa6 | 400 | public static function deleteLineItems($entityId, $entityTable) { |
6a488035 | 401 | if (!$entityId || !$entityTable) { |
9330406e | 402 | return FALSE; |
6a488035 TO |
403 | } |
404 | ||
405 | if ($entityId && !is_array($entityId)) { | |
be2fb01f | 406 | $entityId = [$entityId]; |
6a488035 TO |
407 | } |
408 | ||
de1c25e1 | 409 | $query = "DELETE FROM civicrm_line_item where entity_id IN ('" . implode("','", $entityId) . "') AND entity_table = '$entityTable'"; |
6a488035 | 410 | $dao = CRM_Core_DAO::executeQuery($query); |
9330406e | 411 | return TRUE; |
6a488035 TO |
412 | } |
413 | ||
414 | /** | |
100fef9d | 415 | * Process price set and line items. |
dd244018 | 416 | * |
100fef9d | 417 | * @param int $entityId |
414c1420 TO |
418 | * @param array $lineItem |
419 | * Line item array. | |
6a488035 | 420 | * @param object $contributionDetails |
414c1420 TO |
421 | * @param string $entityTable |
422 | * Entity table. | |
6a488035 | 423 | * |
dd244018 EM |
424 | * @param bool $update |
425 | * | |
6a488035 | 426 | * @return void |
6a488035 | 427 | */ |
00be9182 | 428 | public static function processPriceSet($entityId, $lineItem, $contributionDetails = NULL, $entityTable = 'civicrm_contribution', $update = FALSE) { |
6a488035 TO |
429 | if (!$entityId || !is_array($lineItem) |
430 | || CRM_Utils_system::isNull($lineItem) | |
431 | ) { | |
432 | return; | |
433 | } | |
421dfaa6 | 434 | |
8cf6bd83 | 435 | foreach ($lineItem as $priceSetId => &$values) { |
6a488035 TO |
436 | if (!$priceSetId) { |
437 | continue; | |
438 | } | |
439 | ||
8cf6bd83 | 440 | foreach ($values as &$line) { |
78662b87 PN |
441 | if (empty($line['entity_table'])) { |
442 | $line['entity_table'] = $entityTable; | |
443 | } | |
34a100a7 EM |
444 | if (empty($line['entity_id'])) { |
445 | $line['entity_id'] = $entityId; | |
446 | } | |
22e263ad | 447 | if (!empty($line['membership_type_id'])) { |
79ebec7b | 448 | $line['entity_table'] = 'civicrm_membership'; |
8aa7457a | 449 | } |
79ebec7b PN |
450 | if (!empty($contributionDetails->id)) { |
451 | $line['contribution_id'] = $contributionDetails->id; | |
452 | if ($line['entity_table'] == 'civicrm_contribution') { | |
453 | $line['entity_id'] = $contributionDetails->id; | |
7d3f62f6 | 454 | } |
75d83bd0 | 455 | // CRM-19094: entity_table is set to civicrm_membership then ensure |
456 | // the entityId is set to membership ID not contribution by default | |
41ef4d67 | 457 | elseif ($line['entity_table'] == 'civicrm_membership' && !empty($line['entity_id']) && $line['entity_id'] == $contributionDetails->id) { |
c77986c0 | 458 | $membershipId = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipPayment', $contributionDetails->id, 'membership_id', 'contribution_id'); |
459 | if ($membershipId && (int) $membershipId !== (int) $line['entity_id']) { | |
460 | $line['entity_id'] = $membershipId; | |
be2fb01f | 461 | Civi::log()->warning('Per https://lab.civicrm.org/dev/core/issues/15 this data fix should not be required. Please log a ticket at https://lab.civicrm.org/dev/core with steps to get this.', ['civi.tag' => 'deprecated']); |
c77986c0 | 462 | } |
75d83bd0 | 463 | } |
a7886853 | 464 | } |
c206647d | 465 | |
6a488035 TO |
466 | // if financial type is not set and if price field value is NOT NULL |
467 | // get financial type id of price field value | |
8cc574cf | 468 | if (!empty($line['price_field_value_id']) && empty($line['financial_type_id'])) { |
9da8dc8c | 469 | $line['financial_type_id'] = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceFieldValue', $line['price_field_value_id'], 'financial_type_id'); |
6a488035 TO |
470 | } |
471 | $lineItems = CRM_Price_BAO_LineItem::create($line); | |
472 | if (!$update && $contributionDetails) { | |
8cf6bd83 PN |
473 | $financialItem = CRM_Financial_BAO_FinancialItem::add($lineItems, $contributionDetails); |
474 | $line['financial_item_id'] = $financialItem->id; | |
43c8d1dd | 475 | if (!empty($line['tax_amount'])) { |
0b7bd9dd | 476 | CRM_Financial_BAO_FinancialItem::add($lineItems, $contributionDetails, TRUE); |
477 | } | |
6a488035 TO |
478 | } |
479 | } | |
480 | } | |
8cf6bd83 PN |
481 | if (!$update && $contributionDetails) { |
482 | CRM_Core_BAO_FinancialTrxn::createDeferredTrxn($lineItem, $contributionDetails); | |
483 | } | |
421dfaa6 | 484 | } |
6a488035 | 485 | |
ffd93213 | 486 | /** |
100fef9d | 487 | * @param int $entityId |
ffd93213 EM |
488 | * @param string $entityTable |
489 | * @param $amount | |
100fef9d | 490 | * @param array $otherParams |
ffd93213 | 491 | */ |
6a488035 | 492 | public static function syncLineItems($entityId, $entityTable = 'civicrm_contribution', $amount, $otherParams = NULL) { |
ba1dcfda | 493 | if (!$entityId || CRM_Utils_System::isNull($amount)) { |
6a488035 | 494 | return; |
ba1dcfda | 495 | } |
6a488035 TO |
496 | |
497 | $from = " civicrm_line_item li | |
498 | LEFT JOIN civicrm_price_field pf ON pf.id = li.price_field_id | |
499 | LEFT JOIN civicrm_price_set ps ON ps.id = pf.price_set_id "; | |
500 | ||
421dfaa6 | 501 | $set = " li.unit_price = %3, |
6a488035 TO |
502 | li.line_total = %3 "; |
503 | ||
421dfaa6 | 504 | $where = " li.entity_id = %1 AND |
6a488035 TO |
505 | li.entity_table = %2 "; |
506 | ||
be2fb01f CW |
507 | $params = [ |
508 | 1 => [$entityId, 'Integer'], | |
509 | 2 => [$entityTable, 'String'], | |
510 | 3 => [$amount, 'Float'], | |
511 | ]; | |
6a488035 TO |
512 | |
513 | if ($entityTable == 'civicrm_contribution') { | |
514 | $entityName = 'default_contribution_amount'; | |
515 | $where .= " AND ps.name = %4 "; | |
be2fb01f | 516 | $params[4] = [$entityName, 'String']; |
421dfaa6 | 517 | } |
6a488035 TO |
518 | elseif ($entityTable == 'civicrm_participant') { |
519 | $from .= " | |
520 | LEFT JOIN civicrm_price_set_entity cpse ON cpse.price_set_id = ps.id | |
521 | LEFT JOIN civicrm_price_field_value cpfv ON cpfv.price_field_id = pf.id and cpfv.label = %4 "; | |
522 | $set .= " ,li.label = %4, | |
523 | li.price_field_value_id = cpfv.id "; | |
524 | $where .= " AND cpse.entity_table = 'civicrm_event' AND cpse.entity_id = %5 "; | |
ba1dcfda | 525 | $amount = empty($amount) ? 0 : $amount; |
be2fb01f CW |
526 | $params += [ |
527 | 4 => [$otherParams['fee_label'], 'String'], | |
528 | 5 => [$otherParams['event_id'], 'String'], | |
529 | ]; | |
6a488035 TO |
530 | } |
531 | ||
421dfaa6 | 532 | $query = " |
6a488035 TO |
533 | UPDATE $from |
534 | SET $set | |
421dfaa6 | 535 | WHERE $where |
6a488035 TO |
536 | "; |
537 | ||
538 | CRM_Core_DAO::executeQuery($query, $params); | |
539 | } | |
540 | ||
ba1dcfda | 541 | /** |
100fef9d | 542 | * Build line items array. |
ea3ddccf | 543 | * |
414c1420 TO |
544 | * @param array $params |
545 | * Form values. | |
6a488035 | 546 | * |
414c1420 TO |
547 | * @param string $entityId |
548 | * Entity id. | |
6a488035 | 549 | * |
414c1420 TO |
550 | * @param string $entityTable |
551 | * Entity Table. | |
6a488035 | 552 | * |
ea3ddccf | 553 | * @param bool $isRelatedID |
6a488035 | 554 | */ |
00be9182 | 555 | public static function getLineItemArray(&$params, $entityId = NULL, $entityTable = 'contribution', $isRelatedID = FALSE) { |
6a488035 | 556 | if (!$entityId) { |
82cc6775 | 557 | $priceSetDetails = CRM_Price_BAO_PriceSet::getDefaultPriceSet($entityTable); |
61bfc595 | 558 | $totalAmount = CRM_Utils_Array::value('partial_payment_total', $params, CRM_Utils_Array::value('total_amount', $params)); |
82cc6775 | 559 | $financialType = CRM_Utils_Array::value('financial_type_id', $params); |
6a488035 | 560 | foreach ($priceSetDetails as $values) { |
c206647d | 561 | if ($entityTable == 'membership') { |
82cc6775 PN |
562 | if ($isRelatedID != $values['membership_type_id']) { |
563 | continue; | |
564 | } | |
565 | if (!$totalAmount) { | |
566 | $totalAmount = $values['amount']; | |
567 | } | |
568 | $financialType = $values['financial_type_id']; | |
569 | } | |
be2fb01f | 570 | $params['line_item'][$values['setID']][$values['priceFieldID']] = [ |
6a488035 TO |
571 | 'price_field_id' => $values['priceFieldID'], |
572 | 'price_field_value_id' => $values['priceFieldValueID'], | |
573 | 'label' => $values['label'], | |
574 | 'qty' => 1, | |
82cc6775 PN |
575 | 'unit_price' => $totalAmount, |
576 | 'line_total' => $totalAmount, | |
577 | 'financial_type_id' => $financialType, | |
21dfd5f5 | 578 | 'membership_type_id' => $values['membership_type_id'], |
be2fb01f | 579 | ]; |
82cc6775 | 580 | break; |
6a488035 | 581 | } |
421dfaa6 | 582 | } |
6a488035 TO |
583 | else { |
584 | $setID = NULL; | |
464bb009 | 585 | $totalEntityId = count($entityId); |
2a131e0c PN |
586 | if ($entityTable == 'contribution') { |
587 | $isRelatedID = TRUE; | |
588 | } | |
464bb009 | 589 | foreach ($entityId as $id) { |
77dbdcbc | 590 | $lineItems = CRM_Price_BAO_LineItem::getLineItems($id, $entityTable, FALSE, TRUE, $isRelatedID); |
464bb009 | 591 | foreach ($lineItems as $key => $values) { |
32cb2feb | 592 | if (!$setID && $values['price_field_id']) { |
9da8dc8c | 593 | $setID = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', $values['price_field_id'], 'price_set_id'); |
594 | $params['is_quick_config'] = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $setID, 'is_quick_config'); | |
464bb009 | 595 | } |
a7488080 | 596 | if (!empty($params['is_quick_config']) && array_key_exists('total_amount', $params) |
353ffa53 TO |
597 | && $totalEntityId == 1 |
598 | ) { | |
464bb009 PN |
599 | $values['line_total'] = $values['unit_price'] = $params['total_amount']; |
600 | } | |
601 | $values['id'] = $key; | |
602 | $params['line_item'][$setID][$key] = $values; | |
6a488035 | 603 | } |
6a488035 TO |
604 | } |
605 | } | |
606 | } | |
9849720e | 607 | |
1cb09518 | 608 | /** |
609 | * Build the line items for the submitted price field. | |
610 | * | |
611 | * This is when first building them - not an update where an entityId is already present | |
612 | * as this is intended as a subfunction of that. Ideally getLineItemArray would call this | |
613 | * (resolving to the same format regardless of what type of price set is being used first). | |
614 | * | |
615 | * @param array $priceParams | |
616 | * These are per the way the form processes them - ie | |
617 | * ['price_1' => 1, 'price_2' => 8] | |
618 | * This would mean price field id 1, option 1 (or 1 unit if using is_enter_qty). | |
619 | * @param float|NULL $overrideAmount | |
620 | * Optional override of the amount. | |
621 | * | |
622 | * @param int|NULL $financialTypeID | |
623 | * Financial type ID is the type should be overridden. | |
624 | * | |
625 | * @return array | |
626 | * Line items formatted for processing. These will look like | |
627 | * [4] => ['price_field_id' => 4, 'price_field_value_id' => x, 'label....qty...unit_price...line_total...financial_type_id] | |
628 | * [5] => ['price_field_id' => 5, 'price_field_value_id' => x, 'label....qty...unit_price...line_total...financial_type_id] | |
629 | * | |
630 | */ | |
631 | public static function buildLineItemsForSubmittedPriceField($priceParams, $overrideAmount = NULL, $financialTypeID = NULL) { | |
be2fb01f | 632 | $lineItems = []; |
1cb09518 | 633 | foreach ($priceParams as $key => $value) { |
634 | $priceField = self::getPriceFieldMetaData($key); | |
635 | ||
636 | if ($priceField['html_type'] === 'Text') { | |
637 | $valueSpec = reset($priceField['values']); | |
638 | } | |
639 | else { | |
640 | $valueSpec = $priceField['values'][$value]; | |
641 | } | |
642 | $qty = $priceField['is_enter_qty'] ? $value : 1; | |
643 | $lineItems[$priceField['id']] = [ | |
644 | 'price_field_id' => $priceField['id'], | |
645 | 'price_field_value_id' => $valueSpec['id'], | |
646 | 'label' => $valueSpec['label'], | |
647 | 'qty' => $qty, | |
648 | 'unit_price' => $overrideAmount ?: $valueSpec['amount'], | |
649 | 'line_total' => $qty * ($overrideAmount ?: $valueSpec['amount']), | |
650 | 'financial_type_id' => $financialTypeID ?: $valueSpec['financial_type_id'], | |
651 | 'membership_type_id' => $valueSpec['membership_type_id'], | |
652 | 'price_set_id' => $priceField['price_set_id'], | |
653 | ]; | |
654 | } | |
655 | return $lineItems; | |
656 | } | |
657 | ||
f6e96aa8 | 658 | /** |
659 | * Function to update related contribution of a entity and | |
660 | * add/update/cancel financial records | |
661 | * | |
662 | * @param array $params | |
663 | * @param int $entityID | |
664 | * @param int $entity | |
665 | * @param int $contributionId | |
666 | * @param $feeBlock | |
667 | * @param array $lineItems | |
f6e96aa8 | 668 | * |
669 | */ | |
670 | public static function changeFeeSelections( | |
671 | $params, | |
672 | $entityID, | |
673 | $entity, | |
674 | $contributionId, | |
675 | $feeBlock, | |
6dde7f04 | 676 | $lineItems |
f6e96aa8 | 677 | ) { |
678 | $entityTable = "civicrm_" . $entity; | |
679 | CRM_Price_BAO_PriceSet::processAmount($feeBlock, | |
680 | $params, $lineItems | |
681 | ); | |
682 | // initialize empty Lineitem instance to call protected helper functions | |
683 | $lineItemObj = new CRM_Price_BAO_LineItem(); | |
684 | ||
685 | // fetch submitted LineItems from input params and feeBlock information | |
f7620bfe | 686 | $submittedLineItems = $lineItemObj->getSubmittedLineItems($params, $feeBlock); |
f6e96aa8 | 687 | |
f7620bfe | 688 | $requiredChanges = $lineItemObj->getLineItemsToAlter($submittedLineItems, $entityID, $entity); |
f6e96aa8 | 689 | |
f6e96aa8 | 690 | // get financial information that need to be recorded on basis on submitted price field value IDs |
7b9065ce | 691 | if (!empty($requiredChanges['line_items_to_cancel']) || !empty($requiredChanges['line_items_to_update'])) { |
692 | // @todo - this IF is to get this through PR merge but I suspect that it should not | |
693 | // be necessary & is masking something else. | |
2661ce11 | 694 | $financialItemsArray = $lineItemObj->getAdjustedFinancialItemsToRecord( |
7b9065ce | 695 | $entityID, |
696 | $entityTable, | |
697 | $contributionId, | |
698 | array_keys($requiredChanges['line_items_to_cancel']), | |
699 | $requiredChanges['line_items_to_update'] | |
700 | ); | |
701 | } | |
f6e96aa8 | 702 | |
703 | // update line item with changed line total and other information | |
704 | $totalParticipant = $participantCount = 0; | |
be2fb01f | 705 | $amountLevel = []; |
f7620bfe | 706 | if (!empty($requiredChanges['line_items_to_update'])) { |
707 | foreach ($requiredChanges['line_items_to_update'] as $priceFieldValueID => $value) { | |
f6e96aa8 | 708 | $amountLevel[] = $value['label'] . ' - ' . (float) $value['qty']; |
709 | if ($entity == 'participant' && isset($value['participant_count'])) { | |
f6e96aa8 | 710 | $totalParticipant += $value['participant_count']; |
711 | } | |
f6e96aa8 | 712 | } |
713 | } | |
714 | ||
e0f58893 | 715 | foreach (array_merge($requiredChanges['line_items_to_resurrect'], $requiredChanges['line_items_to_cancel'], $requiredChanges['line_items_to_update']) as $lineItemToAlter) { |
716 | // Must use BAO rather than api because a bad line it in the api which we want to avoid. | |
717 | CRM_Price_BAO_LineItem::create($lineItemToAlter); | |
718 | } | |
f6e96aa8 | 719 | |
7b9065ce | 720 | $lineItemObj->addLineItemOnChangeFeeSelection($requiredChanges['line_items_to_add'], $entityID, $entityTable, $contributionId); |
721 | ||
f6e96aa8 | 722 | $count = 0; |
723 | if ($entity == 'participant') { | |
724 | $count = count(CRM_Event_BAO_Participant::getParticipantIds($contributionId)); | |
725 | } | |
726 | else { | |
be2fb01f | 727 | $count = CRM_Utils_Array::value('count', civicrm_api3('MembershipPayment', 'getcount', ['contribution_id' => $contributionId])); |
f6e96aa8 | 728 | } |
729 | if ($count > 1) { | |
730 | $updatedAmount = CRM_Price_BAO_LineItem::getLineTotal($contributionId); | |
731 | } | |
732 | else { | |
733 | $updatedAmount = CRM_Utils_Array::value('amount', $params, CRM_Utils_Array::value('total_amount', $params)); | |
734 | } | |
735 | if (strlen($params['tax_amount']) != 0) { | |
736 | $taxAmount = $params['tax_amount']; | |
737 | } | |
738 | else { | |
739 | $taxAmount = "NULL"; | |
740 | } | |
741 | $displayParticipantCount = ''; | |
742 | if ($totalParticipant > 0) { | |
743 | $displayParticipantCount = ' Participant Count -' . $totalParticipant; | |
744 | } | |
745 | $updateAmountLevel = NULL; | |
746 | if (!empty($amountLevel)) { | |
747 | $updateAmountLevel = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $amountLevel) . $displayParticipantCount . CRM_Core_DAO::VALUE_SEPARATOR; | |
748 | } | |
6dde7f04 | 749 | $trxn = $lineItemObj->_recordAdjustedAmt($updatedAmount, $contributionId, $taxAmount, $updateAmountLevel); |
217da646 | 750 | $contributionStatus = CRM_Core_PseudoConstant::getName('CRM_Contribute_DAO_Contribution', 'contribution_status_id', CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $contributionId, 'contribution_status_id')); |
751 | ||
f6e96aa8 | 752 | if (!empty($financialItemsArray)) { |
753 | foreach ($financialItemsArray as $updateFinancialItemInfoValues) { | |
745ff069 | 754 | $newFinancialItem = CRM_Financial_BAO_FinancialItem::create($updateFinancialItemInfoValues); |
755 | // record reverse transaction only if Contribution is Completed because for pending refund or | |
756 | // partially paid we are already recording the surplus owed or refund amount | |
6ba3b65c | 757 | if (!empty($updateFinancialItemInfoValues['financialTrxn']) && ($contributionStatus == 'Completed')) { |
be2fb01f | 758 | $updateFinancialItemInfoValues = array_merge($updateFinancialItemInfoValues['financialTrxn'], [ |
745ff069 | 759 | 'entity_id' => $newFinancialItem->id, |
760 | 'entity_table' => 'civicrm_financial_item', | |
be2fb01f | 761 | ]); |
3137781d | 762 | $reverseTrxn = CRM_Core_BAO_FinancialTrxn::create($updateFinancialItemInfoValues); |
745ff069 | 763 | // record reverse entity financial trxn linked to membership's related contribution |
be2fb01f | 764 | civicrm_api3('EntityFinancialTrxn', 'create', [ |
745ff069 | 765 | 'entity_table' => "civicrm_contribution", |
766 | 'entity_id' => $contributionId, | |
767 | 'financial_trxn_id' => $reverseTrxn->id, | |
768 | 'amount' => $reverseTrxn->total_amount, | |
be2fb01f | 769 | ]); |
745ff069 | 770 | unset($updateFinancialItemInfoValues['financialTrxn']); |
f6e96aa8 | 771 | } |
c46645ba | 772 | elseif (!empty($updateFinancialItemInfoValues['link-financial-trxn']) && $newFinancialItem->amount != 0) { |
be2fb01f | 773 | civicrm_api3('EntityFinancialTrxn', 'create', [ |
6ba3b65c | 774 | 'entity_id' => $newFinancialItem->id, |
775 | 'entity_table' => 'civicrm_financial_item', | |
776 | 'financial_trxn_id' => $trxn->id, | |
777 | 'amount' => $newFinancialItem->amount, | |
be2fb01f | 778 | ]); |
6ba3b65c | 779 | unset($updateFinancialItemInfoValues['link-financial-trxn']); |
780 | } | |
f6e96aa8 | 781 | } |
782 | } | |
783 | ||
e0f58893 | 784 | // @todo - it may be that trxn_id is always empty - flush out scenarios. Add tests. |
be2fb01f | 785 | $trxnId = !empty($trxn->id) ? ['id' => $trxn->id] : []; |
e0f58893 | 786 | $lineItemObj->addFinancialItemsOnLineItemsChange(array_merge($requiredChanges['line_items_to_add'], $requiredChanges['line_items_to_resurrect']), $entityID, $entityTable, $contributionId, $trxnId); |
f6e96aa8 | 787 | |
788 | // update participant fee_amount column | |
f7620bfe | 789 | $lineItemObj->updateEntityRecordOnChangeFeeSelection($params, $entityID, $entity); |
f6e96aa8 | 790 | } |
791 | ||
f6e96aa8 | 792 | /** |
7b9065ce | 793 | * Function to retrieve financial items that need to be recorded as result of changed fee |
f6e96aa8 | 794 | * |
795 | * @param int $entityID | |
796 | * @param string $entityTable | |
797 | * @param int $contributionID | |
7b9065ce | 798 | * @param array $priceFieldValueIDsToCancel |
799 | * @param array $lineItemsToUpdate | |
f6e96aa8 | 800 | * |
801 | * @return array | |
971e129b | 802 | * List of formatted reverse Financial Items to be recorded |
f6e96aa8 | 803 | */ |
2661ce11 | 804 | protected function getAdjustedFinancialItemsToRecord($entityID, $entityTable, $contributionID, $priceFieldValueIDsToCancel, $lineItemsToUpdate) { |
f6e96aa8 | 805 | $previousLineItems = CRM_Price_BAO_LineItem::getLineItems($entityID, str_replace('civicrm_', '', $entityTable)); |
806 | ||
be2fb01f | 807 | $financialItemsArray = []; |
667f9091 | 808 | $financialItemResult = $this->getNonCancelledFinancialItems($entityID, $entityTable); |
7d58c44a | 809 | foreach ($financialItemResult as $updateFinancialItemInfoValues) { |
f6e96aa8 | 810 | $updateFinancialItemInfoValues['transaction_date'] = date('YmdHis'); |
7b9065ce | 811 | |
812 | // the below params are not needed as we are creating new financial item | |
f6e96aa8 | 813 | $previousFinancialItemID = $updateFinancialItemInfoValues['id']; |
7b9065ce | 814 | $totalFinancialAmount = $this->checkFinancialItemTotalAmountByLineItemID($updateFinancialItemInfoValues['entity_id']); |
f6e96aa8 | 815 | unset($updateFinancialItemInfoValues['id']); |
816 | unset($updateFinancialItemInfoValues['created_date']); | |
7b9065ce | 817 | |
f6e96aa8 | 818 | // if not submitted and difference is not 0 make it negative |
7b9065ce | 819 | if ((empty($lineItemsToUpdate) || (in_array($updateFinancialItemInfoValues['price_field_value_id'], $priceFieldValueIDsToCancel) && |
820 | $totalFinancialAmount == $updateFinancialItemInfoValues['amount']) | |
821 | ) && $updateFinancialItemInfoValues['amount'] > 0 | |
822 | ) { | |
f6e96aa8 | 823 | // INSERT negative financial_items |
824 | $updateFinancialItemInfoValues['amount'] = -$updateFinancialItemInfoValues['amount']; | |
825 | // reverse the related financial trxn too | |
f7620bfe | 826 | $updateFinancialItemInfoValues['financialTrxn'] = $this->getRelatedCancelFinancialTrxn($previousFinancialItemID); |
f6e96aa8 | 827 | if ($previousLineItems[$updateFinancialItemInfoValues['entity_id']]['tax_amount']) { |
828 | $updateFinancialItemInfoValues['tax']['amount'] = -($previousLineItems[$updateFinancialItemInfoValues['entity_id']]['tax_amount']); | |
8bbe8139 | 829 | $updateFinancialItemInfoValues['tax']['description'] = $this->getSalesTaxTerm(); |
f6e96aa8 | 830 | } |
831 | // INSERT negative financial_items for tax amount | |
7b9065ce | 832 | $financialItemsArray[$updateFinancialItemInfoValues['entity_id']] = $updateFinancialItemInfoValues; |
f6e96aa8 | 833 | } |
2661ce11 | 834 | // INSERT a financial item to record surplus/lesser amount when a text price fee is changed |
6ba3b65c | 835 | elseif (!empty($lineItemsToUpdate) && |
836 | $lineItemsToUpdate[$updateFinancialItemInfoValues['price_field_value_id']]['html_type'] == 'Text' && | |
837 | $updateFinancialItemInfoValues['amount'] > 0 | |
838 | ) { | |
2661ce11 | 839 | // calculate the amount difference, considered as financial item amount |
840 | $updateFinancialItemInfoValues['amount'] = $lineItemsToUpdate[$updateFinancialItemInfoValues['price_field_value_id']]['line_total'] - $totalFinancialAmount; | |
841 | // add a flag, later used to link financial trxn and this new financial item | |
6ba3b65c | 842 | $updateFinancialItemInfoValues['link-financial-trxn'] = TRUE; |
2661ce11 | 843 | if ($previousLineItems[$updateFinancialItemInfoValues['entity_id']]['tax_amount']) { |
844 | $updateFinancialItemInfoValues['tax']['amount'] = $lineItemsToUpdate[$updateFinancialItemInfoValues['entity_id']]['tax_amount'] - $previousLineItems[$updateFinancialItemInfoValues['entity_id']]['tax_amount']; | |
845 | $updateFinancialItemInfoValues['tax']['description'] = $this->getSalesTaxTerm(); | |
846 | } | |
6ba3b65c | 847 | $financialItemsArray[$updateFinancialItemInfoValues['entity_id']] = $updateFinancialItemInfoValues; |
848 | } | |
f6e96aa8 | 849 | } |
850 | ||
851 | return $financialItemsArray; | |
852 | } | |
853 | ||
7b9065ce | 854 | /** |
855 | * Helper function to return sum of financial item's amount related to a line-item | |
856 | * @param array $lineItemID | |
857 | * | |
858 | * @return float $financialItem | |
859 | */ | |
860 | protected function checkFinancialItemTotalAmountByLineItemID($lineItemID) { | |
861 | return CRM_Core_DAO::singleValueQuery(" | |
862 | SELECT SUM(amount) | |
863 | FROM civicrm_financial_item | |
864 | WHERE entity_table = 'civicrm_line_item' AND entity_id = {$lineItemID} | |
865 | "); | |
866 | } | |
867 | ||
f6e96aa8 | 868 | /** |
869 | * Helper function to retrieve submitted line items from form values $inputParams and used $feeBlock | |
870 | * | |
871 | * @param array $inputParams | |
872 | * @param array $feeBlock | |
873 | * | |
874 | * @return array | |
971e129b | 875 | * List of submitted line items |
f6e96aa8 | 876 | */ |
f7620bfe | 877 | protected function getSubmittedLineItems($inputParams, $feeBlock) { |
be2fb01f | 878 | $submittedLineItems = []; |
f6e96aa8 | 879 | foreach ($feeBlock as $id => $values) { |
880 | CRM_Price_BAO_LineItem::format($id, $inputParams, $values, $submittedLineItems); | |
881 | } | |
882 | ||
883 | return $submittedLineItems; | |
884 | } | |
885 | ||
886 | /** | |
e0f58893 | 887 | * Helper function to retrieve line items that need to be altered. |
888 | * | |
889 | * We iterate through the previous line items for the given entity to determine | |
890 | * what alterations to line items need to be made to reflect the new line items. | |
891 | * | |
892 | * There are 4 possible changes required - per the keys in the return array. | |
f6e96aa8 | 893 | * |
894 | * @param array $submittedLineItems | |
895 | * @param int $entityID | |
896 | * @param string $entity | |
897 | * | |
898 | * @return array | |
971e129b | 899 | * Array of line items to alter with the following keys |
e0f58893 | 900 | * - line_items_to_add. If the line items required are new radio options that |
901 | * have not previously been set then we should add line items for them | |
902 | * - line_items_to_update. If we have already been an active option and a change has | |
903 | * happened then it should be in this array. | |
904 | * - line_items_to_cancel. Line items currently selected but not selected in the new selection. | |
905 | * These need to be zero'd out. | |
906 | * - line_items_to_resurrect. Line items previously selected and then deselected. These need to be | |
907 | * re-enabled rather than a new one added. | |
f6e96aa8 | 908 | */ |
f7620bfe | 909 | protected function getLineItemsToAlter($submittedLineItems, $entityID, $entity) { |
f6e96aa8 | 910 | $previousLineItems = CRM_Price_BAO_LineItem::getLineItems($entityID, $entity); |
911 | ||
912 | $lineItemsToAdd = $submittedLineItems; | |
be2fb01f | 913 | $lineItemsToUpdate = []; |
f6e96aa8 | 914 | $submittedPriceFieldValueIDs = array_keys($submittedLineItems); |
be2fb01f | 915 | $lineItemsToCancel = $lineItemsToResurrect = []; |
f6e96aa8 | 916 | |
917 | foreach ($previousLineItems as $id => $previousLineItem) { | |
f6e96aa8 | 918 | if (in_array($previousLineItem['price_field_value_id'], $submittedPriceFieldValueIDs)) { |
5617feb1 | 919 | $submittedLineItem = $submittedLineItems[$previousLineItem['price_field_value_id']]; |
e0f58893 | 920 | if (CRM_Utils_Array::value('html_type', $lineItemsToAdd[$previousLineItem['price_field_value_id']]) == 'Text') { |
921 | // If a 'Text' price field was updated by changing qty value, then we are not adding new line-item but updating the existing one, | |
922 | // because unlike other kind of price-field, it's related price-field-value-id isn't changed and thats why we need to make an | |
923 | // exception here by adding financial item for updated line-item and will reverse any previous financial item entries. | |
be2fb01f | 924 | $lineItemsToUpdate[$previousLineItem['price_field_value_id']] = array_merge($submittedLineItem, ['id' => $id]); |
7b9065ce | 925 | unset($lineItemsToAdd[$previousLineItem['price_field_value_id']]); |
f6e96aa8 | 926 | } |
927 | else { | |
e0f58893 | 928 | $submittedLineItem = $submittedLineItems[$previousLineItem['price_field_value_id']]; |
929 | // for updating the line items i.e. use-case - once deselect-option selecting again | |
930 | if (($previousLineItem['line_total'] != $submittedLineItem['line_total']) | |
931 | || ( | |
932 | // This would be a $0 line item - but why it should be catered to | |
933 | // other than when the above condition is unclear. | |
934 | $submittedLineItem['line_total'] == 0 && $submittedLineItem['qty'] == 1 | |
935 | ) | |
936 | || ( | |
937 | $previousLineItem['qty'] != $submittedLineItem['qty'] | |
938 | ) | |
939 | ) { | |
940 | $lineItemsToUpdate[$previousLineItem['price_field_value_id']] = $submittedLineItem; | |
941 | $lineItemsToUpdate[$previousLineItem['price_field_value_id']]['id'] = $id; | |
942 | // Format is actually '0.00' | |
943 | if ($previousLineItem['line_total'] == 0) { | |
944 | $lineItemsToAdd[$previousLineItem['price_field_value_id']]['id'] = $id; | |
945 | $lineItemsToResurrect[] = $lineItemsToAdd[$previousLineItem['price_field_value_id']]; | |
946 | } | |
947 | } | |
948 | // If there was previously a submitted line item for the same option value then there is | |
949 | // either no change or a qty adjustment. In either case we are not doing an add + reversal. | |
950 | unset($lineItemsToAdd[$previousLineItem['price_field_value_id']]); | |
951 | unset($lineItemsToCancel[$previousLineItem['price_field_value_id']]); | |
f6e96aa8 | 952 | } |
e0f58893 | 953 | } |
954 | else { | |
955 | if (!$this->isCancelled($previousLineItem)) { | |
be2fb01f | 956 | $cancelParams = ['qty' => 0, 'line_total' => 0, 'tax_amount' => 0, 'participant_count' => 0, 'non_deductible_amount' => 0, 'id' => $id]; |
e0f58893 | 957 | $lineItemsToCancel[$previousLineItem['price_field_value_id']] = array_merge($previousLineItem, $cancelParams); |
958 | ||
f6e96aa8 | 959 | } |
960 | } | |
961 | } | |
962 | ||
be2fb01f | 963 | return [ |
f7620bfe | 964 | 'line_items_to_add' => $lineItemsToAdd, |
965 | 'line_items_to_update' => $lineItemsToUpdate, | |
e0f58893 | 966 | 'line_items_to_cancel' => $lineItemsToCancel, |
967 | 'line_items_to_resurrect' => $lineItemsToResurrect, | |
be2fb01f | 968 | ]; |
f6e96aa8 | 969 | } |
970 | ||
e0f58893 | 971 | /** |
972 | * Check if a line item has already been cancelled. | |
973 | * | |
974 | * @param array $lineItem | |
975 | * | |
976 | * @return bool | |
977 | */ | |
978 | protected function isCancelled($lineItem) { | |
979 | if ($lineItem['qty'] == 0 && $lineItem['line_total'] == 0) { | |
980 | return TRUE; | |
981 | } | |
982 | } | |
971e129b | 983 | |
ed0cb2fd | 984 | /** |
7b9065ce | 985 | * Add line Items as result of fee change. |
ed0cb2fd | 986 | * |
987 | * @param array $lineItemsToAdd | |
988 | * @param int $entityID | |
989 | * @param string $entityTable | |
990 | * @param int $contributionID | |
991 | */ | |
992 | protected function addLineItemOnChangeFeeSelection( | |
993 | $lineItemsToAdd, | |
994 | $entityID, | |
995 | $entityTable, | |
996 | $contributionID | |
997 | ) { | |
998 | // if there is no line item to add, do not proceed | |
999 | if (empty($lineItemsToAdd)) { | |
1000 | return; | |
1001 | } | |
1002 | ||
7b9065ce | 1003 | $changedFinancialTypeID = NULL; |
1004 | $updatedContribution = new CRM_Contribute_BAO_Contribution(); | |
1005 | $updatedContribution->id = (int) $contributionID; | |
1006 | // insert financial items | |
ed0cb2fd | 1007 | foreach ($lineItemsToAdd as $priceFieldValueID => $lineParams) { |
be2fb01f | 1008 | $lineParams = array_merge($lineParams, [ |
ed0cb2fd | 1009 | 'entity_table' => $entityTable, |
1010 | 'entity_id' => $entityID, | |
1011 | 'contribution_id' => $contributionID, | |
be2fb01f | 1012 | ]); |
ed0cb2fd | 1013 | if (!array_key_exists('skip', $lineParams)) { |
1014 | self::create($lineParams); | |
1015 | } | |
1016 | } | |
7b9065ce | 1017 | |
1018 | if ($changedFinancialTypeID) { | |
1019 | $updatedContribution->financial_type_id = $changedFinancialTypeID; | |
1020 | $updatedContribution->save(); | |
1021 | } | |
ed0cb2fd | 1022 | } |
1023 | ||
f6e96aa8 | 1024 | /** |
7b9065ce | 1025 | * Add financial transactions when an array of line items is changed. |
f6e96aa8 | 1026 | * |
1027 | * @param array $lineItemsToAdd | |
1028 | * @param int $entityID | |
1029 | * @param string $entityTable | |
1030 | * @param int $contributionID | |
7b9065ce | 1031 | * @param bool $isCreateAdditionalFinancialTrxn |
1032 | * Is there a change to the total balance requiring additional transactions to be created. | |
f6e96aa8 | 1033 | */ |
7b9065ce | 1034 | protected function addFinancialItemsOnLineItemsChange($lineItemsToAdd, $entityID, $entityTable, $contributionID, $isCreateAdditionalFinancialTrxn) { |
1035 | $updatedContribution = new CRM_Contribute_BAO_Contribution(); | |
1036 | $updatedContribution->id = $contributionID; | |
1037 | $updatedContribution->find(TRUE); | |
f6e96aa8 | 1038 | |
f6e96aa8 | 1039 | foreach ($lineItemsToAdd as $priceFieldValueID => $lineParams) { |
be2fb01f | 1040 | $lineParams = array_merge($lineParams, [ |
f6e96aa8 | 1041 | 'entity_table' => $entityTable, |
1042 | 'entity_id' => $entityID, | |
1043 | 'contribution_id' => $contributionID, | |
be2fb01f | 1044 | ]); |
7b9065ce | 1045 | $this->addFinancialItemsOnLineItemChange($isCreateAdditionalFinancialTrxn, $lineParams, $updatedContribution); |
f6e96aa8 | 1046 | } |
1047 | } | |
1048 | ||
1049 | /** | |
1050 | * Helper function to update entity record on change fee selection | |
1051 | * | |
1052 | * @param array $inputParams | |
1053 | * @param int $entityID | |
1054 | * @param string $entity | |
1055 | * | |
1056 | */ | |
f7620bfe | 1057 | protected function updateEntityRecordOnChangeFeeSelection($inputParams, $entityID, $entity) { |
f6e96aa8 | 1058 | $entityTable = "civicrm_{$entity}"; |
1059 | ||
1060 | if ($entity == 'participant') { | |
be2fb01f | 1061 | $partUpdateFeeAmt = ['id' => $entityID]; |
f6e96aa8 | 1062 | $getUpdatedLineItems = "SELECT * |
1063 | FROM civicrm_line_item | |
1064 | WHERE (entity_table = '{$entityTable}' AND entity_id = {$entityID} AND qty > 0)"; | |
1065 | $getUpdatedLineItemsDAO = CRM_Core_DAO::executeQuery($getUpdatedLineItems); | |
be2fb01f | 1066 | $line = []; |
f6e96aa8 | 1067 | while ($getUpdatedLineItemsDAO->fetch()) { |
1068 | $line[$getUpdatedLineItemsDAO->price_field_value_id] = $getUpdatedLineItemsDAO->label . ' - ' . (float) $getUpdatedLineItemsDAO->qty; | |
1069 | } | |
1070 | ||
1071 | $partUpdateFeeAmt['fee_level'] = implode(', ', $line); | |
1072 | $partUpdateFeeAmt['fee_amount'] = $inputParams['amount']; | |
1073 | CRM_Event_BAO_Participant::add($partUpdateFeeAmt); | |
1074 | ||
1075 | //activity creation | |
1076 | CRM_Event_BAO_Participant::addActivityForSelection($entityID, 'Change Registration'); | |
1077 | } | |
1078 | } | |
1079 | ||
1cb09518 | 1080 | /** |
1081 | * Get the metadata for a price field. | |
1082 | * | |
1083 | * @param string|int $key | |
1084 | * Price field id. Either as an integer or as 'price_4' where 4 is the id | |
1085 | * | |
1086 | * @return array | |
1087 | * Metadata for the price field with a values key for option values. | |
1088 | */ | |
1089 | protected static function getPriceFieldMetaData($key) { | |
1090 | $priceFieldID = str_replace('price_', '', $key); | |
1091 | if (!isset(Civi::$statics[__CLASS__]['price_fields'][$priceFieldID])) { | |
1092 | $values = civicrm_api3('PriceFieldValue', 'get', [ | |
1093 | 'price_field_id' => $priceFieldID, | |
1094 | 'return' => [ | |
1095 | 'id', | |
1096 | 'amount', | |
1097 | 'financial_type_id', | |
1098 | 'membership_type_id', | |
1099 | 'label', | |
1100 | 'price_field_id', | |
1101 | 'price_field_id.price_set_id', | |
1102 | 'price_field_id.html_type', | |
1103 | 'is_enter_qty', | |
1104 | ], | |
1105 | ]); | |
1106 | $firstValue = reset($values['values']); | |
1107 | $values = $values['values']; | |
1108 | foreach ($values as $index => $value) { | |
1109 | // Let's be nice to calling functions & ensure membership_type_id is set | |
1110 | // so they don't have to handle notices on it. Handle one place not many. | |
1111 | if (!isset($value['membership_type_id'])) { | |
1112 | $values[$index]['membership_type_id'] = NULL; | |
1113 | } | |
1114 | } | |
1115 | ||
1116 | Civi::$statics[__CLASS__]['price_fields'][$priceFieldID] = [ | |
1117 | 'price_set_id' => $firstValue['price_field_id.price_set_id'], | |
1118 | 'id' => $firstValue['price_field_id'], | |
1119 | 'html_type' => $firstValue['price_field_id.html_type'], | |
1120 | 'is_enter_qty' => !empty($firstValue['is_enter_qty']), | |
1121 | 'values' => $values, | |
1122 | ]; | |
1123 | } | |
1124 | return Civi::$statics[__CLASS__]['price_fields'][$priceFieldID]; | |
1125 | } | |
1126 | ||
f6e96aa8 | 1127 | /** |
1128 | * Helper function to retrieve financial trxn parameters to reverse | |
1129 | * for given financial item identified by $financialItemID | |
1130 | * | |
1131 | * @param int $financialItemID | |
1132 | * | |
1133 | * @return array $financialTrxn | |
1134 | * | |
1135 | */ | |
6dde7f04 | 1136 | protected function _getRelatedCancelFinancialTrxn($financialItemID) { |
1137 | try { | |
be2fb01f | 1138 | $financialTrxn = civicrm_api3('EntityFinancialTrxn', 'getsingle', [ |
6dde7f04 | 1139 | 'entity_table' => 'civicrm_financial_item', |
1140 | 'entity_id' => $financialItemID, | |
be2fb01f | 1141 | 'options' => [ |
6dde7f04 | 1142 | 'sort' => 'id DESC', |
1143 | 'limit' => 1, | |
be2fb01f CW |
1144 | ], |
1145 | 'api.FinancialTrxn.getsingle' => [ | |
6dde7f04 | 1146 | 'id' => "\$value.financial_trxn_id", |
be2fb01f CW |
1147 | ], |
1148 | ]); | |
6dde7f04 | 1149 | } |
1150 | catch (CiviCRM_API3_Exception $e) { | |
be2fb01f | 1151 | return []; |
6dde7f04 | 1152 | } |
745ff069 | 1153 | |
be2fb01f | 1154 | $financialTrxn = array_merge($financialTrxn['api.FinancialTrxn.getsingle'], [ |
745ff069 | 1155 | 'trxn_date' => date('YmdHis'), |
1156 | 'total_amount' => -$financialTrxn['api.FinancialTrxn.getsingle']['total_amount'], | |
1157 | 'net_amount' => -$financialTrxn['api.FinancialTrxn.getsingle']['net_amount'], | |
1158 | 'entity_table' => 'civicrm_financial_item', | |
1159 | 'entity_id' => $financialItemID, | |
be2fb01f | 1160 | ]); |
745ff069 | 1161 | unset($financialTrxn['id']); |
f6e96aa8 | 1162 | |
1163 | return $financialTrxn; | |
1164 | } | |
1165 | ||
1166 | /** | |
1167 | * Record adjusted amount. | |
1168 | * | |
1169 | * @param int $updatedAmount | |
f6e96aa8 | 1170 | * @param int $contributionId |
f6e96aa8 | 1171 | * @param int $taxAmount |
1172 | * @param bool $updateAmountLevel | |
1173 | * | |
1174 | * @return bool|\CRM_Core_BAO_FinancialTrxn | |
1175 | */ | |
6dde7f04 | 1176 | protected function _recordAdjustedAmt($updatedAmount, $contributionId, $taxAmount = NULL, $updateAmountLevel = NULL) { |
1177 | $paidAmount = CRM_Core_BAO_FinancialTrxn::getTotalPayments($contributionId); | |
f6e96aa8 | 1178 | $balanceAmt = $updatedAmount - $paidAmount; |
f6e96aa8 | 1179 | |
1180 | $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); | |
1181 | $partiallyPaidStatusId = array_search('Partially paid', $contributionStatuses); | |
1182 | $pendingRefundStatusId = array_search('Pending refund', $contributionStatuses); | |
1183 | $completedStatusId = array_search('Completed', $contributionStatuses); | |
1184 | ||
1185 | $updatedContributionDAO = new CRM_Contribute_BAO_Contribution(); | |
1186 | $adjustedTrxn = $skip = FALSE; | |
1187 | if ($balanceAmt) { | |
1188 | if ($balanceAmt > 0 && $paidAmount != 0) { | |
1189 | $contributionStatusVal = $partiallyPaidStatusId; | |
1190 | } | |
1191 | elseif ($balanceAmt < 0 && $paidAmount != 0) { | |
1192 | $contributionStatusVal = $pendingRefundStatusId; | |
1193 | } | |
1194 | elseif ($paidAmount == 0) { | |
1195 | //skip updating the contribution status if no payment is made | |
1196 | $skip = TRUE; | |
1197 | $updatedContributionDAO->cancel_date = 'null'; | |
1198 | $updatedContributionDAO->cancel_reason = NULL; | |
1199 | } | |
1200 | // update contribution status and total amount without trigger financial code | |
1201 | // as this is handled in current BAO function used for change selection | |
1202 | $updatedContributionDAO->id = $contributionId; | |
1203 | if (!$skip) { | |
1204 | $updatedContributionDAO->contribution_status_id = $contributionStatusVal; | |
1205 | } | |
1206 | $updatedContributionDAO->total_amount = $updatedContributionDAO->net_amount = $updatedAmount; | |
1207 | $updatedContributionDAO->fee_amount = 0; | |
1208 | $updatedContributionDAO->tax_amount = $taxAmount; | |
1209 | if (!empty($updateAmountLevel)) { | |
1210 | $updatedContributionDAO->amount_level = $updateAmountLevel; | |
1211 | } | |
1212 | $updatedContributionDAO->save(); | |
1213 | // adjusted amount financial_trxn creation | |
1214 | $updatedContribution = CRM_Contribute_BAO_Contribution::getValues( | |
be2fb01f | 1215 | ['id' => $contributionId], |
f6e96aa8 | 1216 | CRM_Core_DAO::$_nullArray, |
1217 | CRM_Core_DAO::$_nullArray | |
1218 | ); | |
1219 | $toFinancialAccount = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($updatedContribution->financial_type_id, 'Accounts Receivable Account is'); | |
be2fb01f | 1220 | $adjustedTrxnValues = [ |
f6e96aa8 | 1221 | 'from_financial_account_id' => NULL, |
1222 | 'to_financial_account_id' => $toFinancialAccount, | |
1223 | 'total_amount' => $balanceAmt, | |
1224 | 'net_amount' => $balanceAmt, | |
1225 | 'status_id' => $completedStatusId, | |
1226 | 'payment_instrument_id' => $updatedContribution->payment_instrument_id, | |
1227 | 'contribution_id' => $updatedContribution->id, | |
1228 | 'trxn_date' => date('YmdHis'), | |
1229 | 'currency' => $updatedContribution->currency, | |
be2fb01f | 1230 | ]; |
f6e96aa8 | 1231 | $adjustedTrxn = CRM_Core_BAO_FinancialTrxn::create($adjustedTrxnValues); |
1232 | } | |
6dde7f04 | 1233 | // CRM-17151: Update the contribution status to completed if balance is zero, |
1234 | // because due to sucessive fee change will leave the related contribution status incorrect | |
1235 | else { | |
1236 | CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_Contribution', $contributionId, 'contribution_status_id', $completedStatusId); | |
1237 | } | |
1238 | ||
f6e96aa8 | 1239 | return $adjustedTrxn; |
1240 | } | |
1241 | ||
5617feb1 | 1242 | /** |
1243 | * Add financial items to reflect line item change. | |
1244 | * | |
1245 | * @param bool $isCreateAdditionalFinancialTrxn | |
1246 | * @param array $lineParams | |
1247 | * @param \CRM_Contribute_BAO_Contribution $updatedContribution | |
5617feb1 | 1248 | */ |
7b9065ce | 1249 | protected function addFinancialItemsOnLineItemChange($isCreateAdditionalFinancialTrxn, $lineParams, $updatedContribution) { |
1250 | $tempFinancialTrxnID = NULL; | |
5617feb1 | 1251 | // don't add financial item for cancelled line item |
1252 | if ($lineParams['qty'] == 0) { | |
7b9065ce | 1253 | return; |
5617feb1 | 1254 | } |
1255 | elseif ($isCreateAdditionalFinancialTrxn) { | |
1256 | // This routine & the return below is super uncomfortable. | |
1257 | // I have refactored to here but don't understand how this would be hit | |
1258 | // and it is how it would be a good thing, given the odd return below which | |
1259 | // does not seem consistent with what is going on. | |
1260 | // I'm tempted to add an e-deprecated into it to confirm my suspicion it only exists to | |
1261 | // cause mental anguish. | |
1262 | // original comment : add financial item if ONLY financial type is changed | |
1263 | if ($lineParams['financial_type_id'] != $updatedContribution->financial_type_id) { | |
1264 | $changedFinancialTypeID = (int) $lineParams['financial_type_id']; | |
be2fb01f | 1265 | $adjustedTrxnValues = [ |
5617feb1 | 1266 | 'from_financial_account_id' => NULL, |
1267 | 'to_financial_account_id' => CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($updatedContribution->payment_instrument_id), | |
1268 | 'total_amount' => $lineParams['line_total'], | |
1269 | 'net_amount' => $lineParams['line_total'], | |
1270 | 'status_id' => $updatedContribution->contribution_status_id, | |
1271 | 'payment_instrument_id' => $updatedContribution->payment_instrument_id, | |
1272 | 'contribution_id' => $updatedContribution->id, | |
1273 | 'is_payment' => TRUE, | |
1274 | // since balance is 0, which means contribution is completed | |
1275 | 'trxn_date' => date('YmdHis'), | |
1276 | 'currency' => $updatedContribution->currency, | |
be2fb01f | 1277 | ]; |
5617feb1 | 1278 | $adjustedTrxn = CRM_Core_BAO_FinancialTrxn::create($adjustedTrxnValues); |
be2fb01f | 1279 | $tempFinancialTrxnID = ['id' => $adjustedTrxn->id]; |
5617feb1 | 1280 | } |
5617feb1 | 1281 | } |
1282 | $lineObj = CRM_Price_BAO_LineItem::retrieve($lineParams, CRM_Core_DAO::$_nullArray); | |
1283 | // insert financial items | |
1284 | // ensure entity_financial_trxn table has a linking of it. | |
1285 | CRM_Financial_BAO_FinancialItem::add($lineObj, $updatedContribution, NULL, $tempFinancialTrxnID); | |
1286 | if (isset($lineObj->tax_amount)) { | |
1287 | CRM_Financial_BAO_FinancialItem::add($lineObj, $updatedContribution, TRUE, $tempFinancialTrxnID); | |
1288 | } | |
5617feb1 | 1289 | } |
1290 | ||
667f9091 | 1291 | /** |
1292 | * Get Financial items, culling out any that have already been reversed. | |
1293 | * | |
1294 | * @param int $entityID | |
1295 | * @param string $entityTable | |
1296 | * | |
1297 | * @return array | |
1298 | * Array of financial items that have not be reversed. | |
1299 | */ | |
1300 | protected function getNonCancelledFinancialItems($entityID, $entityTable) { | |
7b9065ce | 1301 | // gathering necessary info to record negative (deselected) financial_item |
667f9091 | 1302 | $updateFinancialItem = " |
7b9065ce | 1303 | SELECT fi.*, price_field_value_id, financial_type_id, tax_amount |
667f9091 | 1304 | FROM civicrm_financial_item fi LEFT JOIN civicrm_line_item li ON (li.id = fi.entity_id AND fi.entity_table = 'civicrm_line_item') |
1305 | WHERE (li.entity_table = '{$entityTable}' AND li.entity_id = {$entityID}) | |
1306 | GROUP BY li.entity_table, li.entity_id, price_field_value_id, fi.id | |
1307 | "; | |
1308 | $updateFinancialItemInfoDAO = CRM_Core_DAO::executeQuery($updateFinancialItem); | |
1309 | ||
1310 | $financialItemResult = $updateFinancialItemInfoDAO->fetchAll(); | |
be2fb01f | 1311 | $items = []; |
667f9091 | 1312 | foreach ($financialItemResult as $index => $financialItem) { |
1313 | $items[$financialItem['price_field_value_id']][$index] = $financialItem['amount']; | |
1314 | ||
1315 | if (!empty($items[$financialItem['price_field_value_id']])) { | |
1316 | foreach ($items[$financialItem['price_field_value_id']] as $existingItemID => $existingAmount) { | |
1317 | if ($financialItem['amount'] + $existingAmount == 0) { | |
1318 | // Filter both rows as they cancel each other out. | |
1319 | unset($financialItemResult[$index]); | |
1320 | unset($financialItemResult[$existingItemID]); | |
1321 | unset($items['price_field_value_id'][$existingItemID]); | |
1322 | unset($items[$financialItem['price_field_value_id']][$index]); | |
1323 | } | |
1324 | } | |
1325 | ||
1326 | } | |
1327 | ||
1328 | } | |
1329 | return $financialItemResult; | |
1330 | } | |
1331 | ||
8bbe8139 | 1332 | /** |
1333 | * Get the string used to describe the sales tax (eg. VAT, GST). | |
1334 | * | |
1335 | * @return string | |
1336 | */ | |
1337 | protected function getSalesTaxTerm() { | |
1338 | return CRM_Contribute_BAO_Contribution::checkContributeSettings('tax_term'); | |
1339 | } | |
1340 | ||
6a488035 | 1341 | } |