Merge pull request #23635 from eileenmcnaughton/import_unreach2
[civicrm-core.git] / tests / phpunit / CRM / Event / BAO / ChangeFeeSelectionTest.php
1 <?php
2
3 /**
4 * Class CRM_Event_BAO_AdditionalPaymentTest
5 *
6 * @group headless
7 */
8 class CRM_Event_BAO_ChangeFeeSelectionTest extends CiviUnitTestCase {
9
10 protected $_priceSetID;
11
12 protected $_cheapFee = '80.00';
13
14 protected $_expensiveFee = '100.00';
15
16 protected $_veryExpensive = '120.00';
17
18 protected $_noFee = 0;
19
20 protected $expensiveFeeValueID;
21
22 protected $cheapFeeValueID;
23
24 protected $veryExpensiveFeeValueID;
25
26 protected $noFeeID;
27
28 /**
29 * @var int
30 */
31 protected $contributionID;
32
33 /**
34 * @var int
35 */
36 protected $participantID;
37
38 /**
39 * Price set field id.
40 *
41 * @var int
42 */
43 protected $priceSetFieldID;
44
45 /**
46 * @var int
47 */
48 private $_contactId;
49
50 /**
51 * @var int
52 */
53 private $_eventId;
54
55 /**
56 * @var array
57 */
58 private $_feeBlock;
59
60 /**
61 * Set up for test.
62 *
63 * @throws \CRM_Core_Exception
64 * @throws \CiviCRM_API3_Exception
65 */
66 public function setUp(): void {
67 parent::setUp();
68 $this->_contactId = $this->individualCreate();
69 $event = $this->eventCreate(['is_monetary' => 1]);
70 $this->_eventId = $event['id'];
71 $this->_priceSetID = $this->priceSetCreate();
72 CRM_Price_BAO_PriceSet::addTo('civicrm_event', $this->_eventId, $this->_priceSetID);
73 $priceSet = CRM_Price_BAO_PriceSet::getSetDetail($this->_priceSetID, TRUE, FALSE);
74 $priceSet = $priceSet[$this->_priceSetID] ?? NULL;
75 $this->_feeBlock = $priceSet['fields'] ?? NULL;
76 }
77
78 /**
79 * Clean up after test.
80 */
81 public function tearDown(): void {
82 $this->eventDelete($this->_eventId);
83 $this->quickCleanUpFinancialEntities();
84 parent::tearDown();
85 }
86
87 /**
88 * Create an event with a price set.
89 *
90 * @param string $type
91 *
92 * @return int
93 * @throws \CRM_Core_Exception
94 * @throws \CiviCRM_API3_Exception
95 * @todo resolve this with parent function.
96 */
97 protected function priceSetCreate($type = 'Radio') {
98 $paramsSet['title'] = 'Two Options' . substr(sha1(rand()), 0, 4);
99 $paramsSet['name'] = CRM_Utils_String::titleToVar('Two Options') . substr(sha1(rand()), 0, 4);
100 $paramsSet['is_active'] = FALSE;
101 $paramsSet['extends'] = 1;
102
103 $priceSet = CRM_Price_BAO_PriceSet::create($paramsSet);
104
105 if ($type === 'Text') {
106 $paramsField = [
107 'label' => 'Text Price Field',
108 'name' => CRM_Utils_String::titleToVar('text_price_field'),
109 'html_type' => 'Text',
110 'option_label' => ['1' => 'Text Price Field'],
111 'option_name' => ['1' => CRM_Utils_String::titleToVar('text_price_field')],
112 'option_weight' => ['1' => 1],
113 'option_amount' => ['1' => 10],
114 'option_count' => [1 => 1],
115 'is_display_amounts' => 1,
116 'weight' => 1,
117 'options_per_line' => 1,
118 'is_active' => ['1' => 1],
119 'price_set_id' => $priceSet->id,
120 'is_enter_qty' => 1,
121 'financial_type_id' => $this->getFinancialTypeId('Event Fee'),
122 ];
123 }
124 else {
125 /** @noinspection UnNecessaryDoubleQuotesInspection */
126 $paramsField = [
127 'label' => 'Price Field',
128 'name' => CRM_Utils_String::titleToVar('Two Options'),
129 'html_type' => 'Radio',
130 //'price' => $feeTotal,
131 'option_label' => ['1' => 'Expensive Room', '2' => 'Cheap Room', '3' => 'Very Expensive', '4' => 'No Fee'],
132 'option_value' => ['1' => 'E', '2' => 'C', '3' => 'V', '4' => 'N'],
133 'option_name' => ['1' => 'Expensive', '2' => 'Cheap', '3' => 'Very Expensive'],
134 'option_weight' => ['1' => 1, '2' => 2, '3' => 3, '4' => 4],
135 'option_amount' => ['1' => $this->_expensiveFee, '2' => $this->_cheapFee, '3' => $this->_veryExpensive, '4' => $this->_noFee],
136 'option_count' => [1 => 1, 2 => 1, 3 => 1, 4 => 1],
137 'is_display_amounts' => 1,
138 'weight' => 1,
139 'options_per_line' => 1,
140 'is_active' => ['1' => 1],
141 'price_set_id' => $priceSet->id,
142 'is_enter_qty' => 1,
143 'financial_type_id' => $this->getFinancialTypeId('Event Fee'),
144 ];
145 }
146 $field = CRM_Price_BAO_PriceField::create($paramsField);
147 $values = $this->callAPISuccess('PriceFieldValue', 'get', [
148 'price_field_id' => $field->id,
149 'return' => ['id', 'label'],
150 ]);
151 foreach ($values['values'] as $value) {
152 switch ($value['label']) {
153 case 'Expensive Room':
154 $this->expensiveFeeValueID = $value['id'];
155 break;
156
157 case 'Cheap Room':
158 $this->cheapFeeValueID = $value['id'];
159 break;
160
161 case 'Very Expensive':
162 $this->veryExpensiveFeeValueID = $value['id'];
163 break;
164
165 case 'No Fee':
166 $this->noFeeID = $value['id'];
167 break;
168
169 }
170 }
171
172 $this->priceSetFieldID = $field->id;
173 return $priceSet->id;
174 }
175
176 /**
177 * Get the total for the invoice.
178 *
179 * @param int $contributionId
180 *
181 * @return mixed
182 */
183 private function contributionInvoice($contributionId) {
184 $query = "
185 SELECT SUM(line_total) total
186 FROM civicrm_line_item
187 WHERE contribution_id = {$contributionId}";
188 $dao = CRM_Core_DAO::executeQuery($query);
189
190 $this->assertTrue($dao->fetch(), 'Succeeded retrieving invoice total');
191 return $dao->total;
192 }
193
194 /**
195 * Get the total income from the participant record.
196 *
197 * @param int $participantId
198 *
199 * @return mixed
200 */
201 private function totalIncome($participantId) {
202 $query = "
203 SELECT SUM(fi.amount) total
204 FROM civicrm_financial_item fi
205 INNER JOIN civicrm_line_item li ON li.id = fi.entity_id AND fi.entity_table = 'civicrm_line_item'
206 WHERE li.entity_table = 'civicrm_participant' AND li.entity_id = ${participantId}
207 ";
208 $dao = CRM_Core_DAO::executeQuery($query);
209
210 $this->assertTrue($dao->fetch(), 'Succeeded retrieving total Income');
211 return $dao->total;
212 }
213
214 /**
215 * Check the relevant entity balances.
216 *
217 * @param float $amount
218 */
219 private function balanceCheck($amount) {
220 $this->assertEquals($amount, $this->contributionInvoice($this->_contributionId), "Invoice must a total of $amount");
221 $this->assertEquals($amount, $this->totalIncome($this->_participantId), "The recorded income must be $amount ");
222 }
223
224 /**
225 * Prepare records for editing.
226 *
227 * @param null $actualPaidAmt
228 *
229 * @throws \CRM_Core_Exception
230 */
231 public function registerParticipantAndPay($actualPaidAmt = NULL) {
232 $actualPaidAmt = $actualPaidAmt ?: $this->_expensiveFee;
233 $lineItems = CRM_Price_BAO_LineItem::buildLineItemsForSubmittedPriceField(['price_' . $this->priceSetFieldID => $this->expensiveFeeValueID]);
234 $orderParams = [
235 'total_amount' => $this->_expensiveFee,
236 'source' => 'Test set with information',
237 'currency' => 'USD',
238 'receipt_date' => date('Y-m-d') . ' 00:00:00',
239 'contact_id' => $this->_contactId,
240 'financial_type_id' => 4,
241 'payment_instrument_id' => 4,
242 'contribution_status_id' => 'Pending',
243 'receive_date' => date('Y-m-d') . ' 00:00:00',
244 'line_items' => [],
245 'api.Payment.create' => ['total_amount' => $actualPaidAmt],
246 ];
247 foreach ($lineItems as $lineItem) {
248 $orderParams['line_items'][] = [
249 'line_item' => [array_merge($lineItem, ['entity_table' => 'civicrm_participant'])],
250 'params' => [
251 'send_receipt' => 1,
252 'is_pay_later' => 0,
253 'event_id' => $this->_eventId,
254 'register_date' => date('Y-m-d') . ' 00:00:00',
255 'role_id' => 1,
256 'status_id' => 1,
257 'source' => 'Event_' . $this->_eventId,
258 'contact_id' => $this->_contactId,
259 ],
260 ];
261 }
262
263 $order = $this->callAPISuccess('Order', 'create', $orderParams);
264 $this->_contributionId = $order['id'];
265
266 $this->_participantId = $this->callAPISuccess('participant_payment', 'getvalue', [
267 'return' => 'participant_id',
268 'contribution_id' => $this->_contributionId,
269 ]);
270 $this->balanceCheck($this->_expensiveFee);
271 $this->assertEquals(($this->_expensiveFee - $actualPaidAmt), CRM_Contribute_BAO_Contribution::getContributionBalance($this->_contributionId));
272
273 }
274
275 /**
276 * @throws \CRM_Core_Exception
277 * @throws \CiviCRM_API3_Exception
278 */
279 public function testCRM19273() {
280 // When a line item is 'resurrected' the financial_items attached to it are wrong.
281 // We have to skip validatePayments until fixed.
282 $this->isValidateFinancialsOnPostAssert = FALSE;
283 $this->registerParticipantAndPay();
284
285 $priceSetParams['price_' . $this->priceSetFieldID] = $this->cheapFeeValueID;
286 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant');
287 CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
288 $this->balanceCheck($this->_cheapFee);
289
290 $priceSetParams['price_' . $this->priceSetFieldID] = $this->expensiveFeeValueID;
291 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant');
292
293 CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
294
295 $this->balanceCheck($this->_expensiveFee);
296
297 $priceSetParams['price_' . $this->priceSetFieldID] = $this->veryExpensiveFeeValueID;
298 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant');
299 CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
300 $this->balanceCheck($this->_veryExpensive);
301 }
302
303 /**
304 * CRM-21245: Test that Contribution status doesn't changed to 'Pending Refund' from 'Partially Paid' if the partially paid amount is lower then newly selected fee amount
305 *
306 * @throws \CRM_Core_Exception
307 * @throws \CiviCRM_API3_Exception
308 */
309 public function testCRM21245() {
310 $this->registerParticipantAndPay(50);
311 $partiallyPaidContributionStatus = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Partially paid');
312 $this->assertEquals($this->callAPISuccessGetValue('Contribution', ['id' => $this->_contributionId, 'return' => 'contribution_status_id']), $partiallyPaidContributionStatus);
313
314 $priceSetParams['price_' . $this->priceSetFieldID] = $this->veryExpensiveFeeValueID;
315 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant');
316 CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
317 $this->assertEquals($this->callAPISuccessGetValue('Contribution', ['id' => $this->_contributionId, 'return' => 'contribution_status_id']), $partiallyPaidContributionStatus);
318 }
319
320 /**
321 * Test that proper financial items are recorded for cancelled line items
322 *
323 * @throws \CRM_Core_Exception
324 * @throws \CiviCRM_API3_Exception
325 */
326 public function testCRM20611() {
327 $this->registerParticipantAndPay();
328 $actualPaidAmount = 100;
329 $priceSetParams['price_' . $this->priceSetFieldID] = $this->expensiveFeeValueID;
330 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->participantID, 'participant');
331 CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
332 $this->balanceCheck($this->_expensiveFee);
333 $contributionBalance = ($this->_expensiveFee - $actualPaidAmount);
334 $this->assertEquals($contributionBalance, CRM_Contribute_BAO_Contribution::getContributionBalance($this->_contributionId));
335
336 $priceSetParams['price_' . $this->priceSetFieldID] = $this->cheapFeeValueID;
337 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->participantID, 'participant');
338 CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
339 $this->balanceCheck($this->_cheapFee);
340 $contributionBalance = ($this->_cheapFee - $actualPaidAmount);
341 $this->assertEquals($contributionBalance, CRM_Contribute_BAO_Contribution::getContributionBalance($this->_contributionId));
342
343 $this->callAPISuccess('Payment', 'create', [
344 'contribution_id' => $this->_contributionId,
345 'total_amount' => -120,
346 'payment_instrument_id' => 3,
347 'participant_id' => $this->_participantId,
348 ]);
349 $contributionBalance += 120;
350 $this->assertEquals($contributionBalance, CRM_Contribute_BAO_Contribution::getContributionBalance($this->_contributionId));
351
352 // retrieve the cancelled line-item information
353 $cancelledLineItem = $this->callAPISuccessGetSingle('LineItem', [
354 'entity_table' => 'civicrm_participant',
355 'entity_id' => $this->_participantId,
356 'qty' => 0,
357 ]);
358 // retrieve the related financial lin-items
359 $financialItems = $this->callAPISuccess('FinancialItem', 'Get', [
360 'entity_id' => $cancelledLineItem['id'],
361 'entity_table' => 'civicrm_line_item',
362 ]);
363 $this->assertEquals($financialItems['count'], 2, 'Financial Items for Cancelled fee is not proper');
364
365 $expectedAmount = 100.00;
366 foreach ($financialItems['values'] as $id => $financialItem) {
367 $this->assertEquals($expectedAmount, $financialItem['amount']);
368 $this->assertNotEmpty($financialItem['financial_account_id']);
369 $expectedAmount = -$expectedAmount;
370 }
371 }
372
373 /**
374 * Test to ensure that correct financial records are entered on text price field fee change on event registration
375 *
376 * @throws \CRM_Core_Exception
377 * @throws \CiviCRM_API3_Exception
378 */
379 public function testCRM21513() {
380 $this->_priceSetID = $this->priceSetCreate('Text');
381 CRM_Price_BAO_PriceSet::addTo('civicrm_event', $this->_eventId, $this->_priceSetID);
382 $priceSet = CRM_Price_BAO_PriceSet::getSetDetail($this->_priceSetID, TRUE, FALSE);
383 $priceSet = $priceSet[$this->_priceSetID] ?? NULL;
384 $this->_feeBlock = $priceSet['fields'] ?? NULL;
385
386 $params = [
387 'send_receipt' => 1,
388 'is_test' => 0,
389 'is_pay_later' => 0,
390 'event_id' => $this->_eventId,
391 'register_date' => date('Y-m-d') . ' 00:00:00',
392 'role_id' => 1,
393 'status_id' => 1,
394 'source' => 'Event_' . $this->_eventId,
395 'contact_id' => $this->_contactId,
396 ];
397 $participant = $this->callAPISuccess('Participant', 'create', $params);
398 $this->_participantId = $participant['id'];
399 $contributionParams = [
400 'total_amount' => 10,
401 'source' => 'Test set with information',
402 'currency' => 'USD',
403 'receipt_date' => date('Y-m-d') . ' 00:00:00',
404 'contact_id' => $this->_contactId,
405 'financial_type_id' => 4,
406 'payment_instrument_id' => 4,
407 'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_DAO_Contribution', 'contribution_status_id', 'Pending'),
408 'receive_date' => date('Y-m-d') . ' 00:00:00',
409 'skipLineItem' => 1,
410 ];
411
412 $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams);
413 $this->_contributionId = $contribution['id'];
414
415 $this->callAPISuccess('participant_payment', 'create', [
416 'participant_id' => $this->_participantId,
417 'contribution_id' => $this->_contributionId,
418 ]);
419
420 // CASE 1: Choose text price qty 1 (x$10 = $10 amount)
421 $priceSetParams['price_' . $this->priceSetFieldID] = 1;
422 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant');
423 CRM_Price_BAO_PriceSet::processAmount($this->_feeBlock, $priceSetParams, $lineItem);
424 $lineItemVal[$this->_priceSetID] = $lineItem;
425 CRM_Price_BAO_LineItem::processPriceSet($this->_participantId, $lineItemVal, $this->getContributionObject($contribution['id']), 'civicrm_participant');
426
427 // CASE 2: Choose text price qty 3 (x$10 = $30 amount)
428 $priceSetParams['price_' . $this->priceSetFieldID] = 3;
429 $lineItem = CRM_Price_BAO_LineItem::getLineItems($participant['id'], 'participant');
430 CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $participant['id'], 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
431
432 // CASE 3: Choose text price qty 2 (x$10 = $20 amount)
433 $priceSetParams['price_' . $this->priceSetFieldID] = 2;
434 $lineItem = CRM_Price_BAO_LineItem::getLineItems($participant['id'], 'participant');
435 CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $participant['id'], 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
436
437 $financialItems = $this->callAPISuccess('FinancialItem', 'Get', [
438 'entity_table' => 'civicrm_line_item',
439 'entity_id' => ['IN' => array_keys($lineItem)],
440 'sequential' => 1,
441 ]);
442
443 $unpaidStatus = CRM_Core_PseudoConstant::getKey('CRM_Financial_DAO_FinancialItem', 'status_id', 'Unpaid');
444 $expectedResults = [
445 [
446 // when qty 1 is used
447 'amount' => 10.00,
448 'status_id' => $unpaidStatus,
449 'entity_table' => 'civicrm_line_item',
450 'entity_id' => 1,
451 ],
452 [
453 // when qty 3 is used, add the surplus amount i.e. $30 - $10 = $20
454 'amount' => 20.00,
455 'status_id' => $unpaidStatus,
456 'entity_table' => 'civicrm_line_item',
457 'entity_id' => 1,
458 ],
459 [
460 // when qty 2 is used, add the surplus amount i.e. $20 - $30 = -$10
461 'amount' => -10.00,
462 'status_id' => $unpaidStatus,
463 'entity_table' => 'civicrm_line_item',
464 'entity_id' => 1,
465 ],
466 ];
467 // Check if 3 financial items were recorded
468 $this->assertEquals(count($expectedResults), $financialItems['count']);
469 foreach ($expectedResults as $key => $expectedResult) {
470 foreach ($expectedResult as $column => $value) {
471 $this->assertEquals($expectedResult[$column], $financialItems['values'][$key][$column]);
472 }
473 }
474
475 $this->balanceCheck(20);
476 }
477
478 /**
479 * CRM-17151: Test that Contribution status change to 'Completed' if balance is zero.
480 *
481 * @throws \CRM_Core_Exception
482 * @throws \CiviCRM_API3_Exception
483 */
484 public function testCRM17151() {
485 // @todo figure out the financial validation issue - likely a real bug.
486 $this->isValidateFinancialsOnPostAssert = FALSE;
487 $this->registerParticipantAndPay();
488
489 $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
490 $partiallyPaidStatusId = array_search('Partially paid', $contributionStatuses);
491 $pendingRefundStatusId = array_search('Pending refund', $contributionStatuses);
492 $completedStatusId = array_search('Completed', $contributionStatuses);
493 $this->assertDBCompareValue('CRM_Contribute_BAO_Contribution', $this->_contributionId, 'total_amount', 'id', $this->_expensiveFee, "Total Amount equals " . $this->_expensiveFee);
494 $this->assertDBCompareValue('CRM_Contribute_BAO_Contribution', $this->_contributionId, 'contribution_status_id', 'id', $completedStatusId, 'Payment be completed');
495 $priceSetParams['price_' . $this->priceSetFieldID] = $this->cheapFeeValueID;
496 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant');
497 $this->assertEquals($this->_expensiveFee, $lineItem[1]['line_total']);
498 CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
499 $this->assertDBCompareValue('CRM_Contribute_BAO_Contribution', $this->_contributionId, 'total_amount', 'id', $this->_cheapFee, 'Total Amount equals ' . $this->_expensiveFee);
500 $this->assertDBCompareValue('CRM_Contribute_BAO_Contribution', $this->_contributionId, 'contribution_status_id', 'id', $pendingRefundStatusId, 'Contribution must be refunding');
501 $priceSetParams['price_' . $this->priceSetFieldID] = $this->expensiveFeeValueID;
502 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant');
503 $this->assertEquals('0.00', $lineItem[1]['line_total']);
504 $this->assertEquals($this->_cheapFee, $lineItem[2]['line_total']);
505 CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
506 $this->assertDBCompareValue('CRM_Contribute_BAO_Contribution', $this->_contributionId, 'contribution_status_id', 'id', $completedStatusId, 'Contribution must, after complete payment be in state completed');
507 $priceSetParams['price_' . $this->priceSetFieldID] = $this->veryExpensiveFeeValueID;
508 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant');
509 $this->assertEquals($this->_expensiveFee, $lineItem[1]['line_total']);
510 $this->assertEquals('0.00', $lineItem[2]['line_total']);
511 // @todo this doesn't seem to work right even tho it should
512 //$this->assertDBCompareValue('CRM_Contribute_BAO_Contribution', $this->_contributionId, 'total_amount', 'id', $this->_expensiveFee, "Total Amount equals " . $this->_expensiveFee);
513 CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
514 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant');
515 $this->assertEquals('0.00', $lineItem[1]['line_total']);
516 $this->assertEquals('0.00', $lineItem[2]['line_total']);
517 $this->assertEquals($this->_veryExpensive, $lineItem[3]['line_total']);
518 $this->assertDBCompareValue('CRM_Contribute_BAO_Contribution', $this->_contributionId, 'total_amount', 'id', $this->_veryExpensive, "Total Amount equals " . $this->_veryExpensive);
519 $this->assertDBCompareValue('CRM_Contribute_BAO_Contribution', $this->_contributionId, 'contribution_status_id', 'id', $partiallyPaidStatusId, 'Partial Paid');
520 }
521
522 /**
523 * Test that recording a refund when fee selection is 0 works
524 *
525 * @throws \CRM_Core_Exception
526 * @throws \CiviCRM_API3_Exception
527 */
528 public function testRefundWithFeeAmount0() {
529 $this->registerParticipantAndPay();
530 $actualPaidAmount = 100;
531 $priceSetParams['price_' . $this->priceSetFieldID] = $this->expensiveFeeValueID;
532 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->participantID, 'participant');
533 CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
534 $this->balanceCheck($this->_expensiveFee);
535 $contributionBalance = ($this->_expensiveFee - $actualPaidAmount);
536 $this->assertEquals($contributionBalance, CRM_Contribute_BAO_Contribution::getContributionBalance($this->_contributionId));
537
538 $priceSetParams['price_' . $this->priceSetFieldID] = $this->noFeeID;
539 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->participantID, 'participant');
540 CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
541 $this->balanceCheck($this->_noFee);
542 $contributionBalance = ($this->_noFee - $actualPaidAmount);
543 $this->assertEquals($contributionBalance, CRM_Contribute_BAO_Contribution::getContributionBalance($this->_contributionId));
544
545 $this->callAPISuccess('Payment', 'create', [
546 'contribution_id' => $this->_contributionId,
547 'total_amount' => -100,
548 'payment_instrument_id' => 3,
549 'participant_id' => $this->_participantId,
550 ]);
551 $contributionBalance += 100;
552 $this->assertEquals($contributionBalance, CRM_Contribute_BAO_Contribution::getContributionBalance($this->_contributionId));
553
554 // retrieve the cancelled line-item information
555 $cancelledLineItem = $this->callAPISuccessGetSingle('LineItem', [
556 'entity_table' => 'civicrm_participant',
557 'entity_id' => $this->_participantId,
558 'qty' => 0,
559 ]);
560 // retrieve the related financial lin-items
561 $financialItems = $this->callAPISuccess('FinancialItem', 'Get', [
562 'entity_id' => $cancelledLineItem['id'],
563 'entity_table' => 'civicrm_line_item',
564 ]);
565 $this->assertEquals($financialItems['count'], 2, 'Financial Items for Cancelled fee is not proper');
566
567 $expectedAmount = 100.00;
568 foreach ($financialItems['values'] as $id => $financialItem) {
569 $this->assertEquals($expectedAmount, $financialItem['amount']);
570 $this->assertNotEmpty($financialItem['financial_account_id']);
571 $expectedAmount = -$expectedAmount;
572 }
573 }
574
575 /**
576 * dev-financial-40: Test that partial payment entries in entity-financial-trxn table to ensure that reverse transaction is entered
577 *
578 * @throws \CRM_Core_Exception
579 * @throws \CiviCRM_API3_Exception
580 */
581 public function testPartialPaymentEntries() {
582 $this->registerParticipantAndPay($this->_expensiveFee);
583 $priceSetParams['price_' . $this->priceSetFieldID] = $this->veryExpensiveFeeValueID;
584 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->participantID, 'participant');
585 CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
586 $actualResults = $this->callAPISuccess('EntityFinancialTrxn', 'get', ['sequential' => 1, 'entity_table' => 'civicrm_financial_item'])['values'];
587 $this->assertCount(3, $actualResults);
588 $expectedResults = [
589 [
590 'id' => 2,
591 'amount' => 100.0,
592 'entity_id' => 1,
593 'financial_trxn_id' => 1,
594 'entity_table' => 'civicrm_financial_item',
595 ],
596 [
597 'id' => 4,
598 // ensure that reverse entry is entered in the EntityFinancialTrxn table on fee change to greater amount
599 'amount' => -100.0,
600 'entity_id' => 2,
601 'financial_trxn_id' => 2,
602 'entity_table' => 'civicrm_financial_item',
603 ],
604 [
605 'id' => 5,
606 'amount' => 120.00,
607 'entity_id' => 3,
608 'financial_trxn_id' => 2,
609 'entity_table' => 'civicrm_financial_item',
610 ],
611 ];
612 foreach ($expectedResults as $key => $expectedResult) {
613 $this->checkArrayEquals($expectedResult, $actualResults[$key]);
614 }
615 }
616
617 /**
618 * dev-financial-40: Test that refund payment entries in entity-financial-trxn table to ensure that reverse transaction is entered on fee change to lesser amount
619 *
620 * @throws \CRM_Core_Exception
621 * @throws \CiviCRM_API3_Exception
622 */
623 public function testRefundPaymentEntries() {
624 $this->registerParticipantAndPay($this->_expensiveFee);
625 $priceSetParams['price_' . $this->priceSetFieldID] = $this->cheapFeeValueID;
626 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->participantID, 'participant');
627 CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
628 $actualResults = $this->callAPISuccess('EntityFinancialTrxn', 'get', ['sequential' => 1, 'entity_table' => 'civicrm_financial_item', 'return' => ['amount', 'entity_id']])['values'];
629 $expectedResults = [
630 [
631 'id' => 2,
632 'amount' => 100.00,
633 'entity_id' => 1,
634 ],
635 [
636 'id' => 4,
637 // ensure that reverse entry is entered in the EntityFinancialTrxn table
638 'amount' => -100.00,
639 'entity_id' => 2,
640 ],
641 [
642 'id' => 5,
643 'amount' => 80.00,
644 'entity_id' => 3,
645 ],
646 ];
647 foreach ($expectedResults as $key => $expectedResult) {
648 $this->checkArrayEquals($expectedResult, $actualResults[$key]);
649 }
650 }
651
652 }