3 * Class CRM_Event_BAO_AdditionalPaymentTest
6 class CRM_Event_BAO_ChangeFeeSelectionTest
extends CiviUnitTestCase
{
8 protected $_priceSetID;
9 protected $_cheapFee = 80;
10 protected $_expensiveFee = 100;
11 protected $_veryExpensive = 120;
12 protected $expensiveFeeValueID;
13 protected $cheapFeeValueID;
14 protected $veryExpensiveFeeValueID;
19 protected $contributionID;
24 protected $participantID;
31 protected $priceSetFieldID;
36 public function setUp() {
38 $this->_contactId
= $this->individualCreate();
39 $event = $this->eventCreate(array('is_monetary' => 1));
40 $this->_eventId
= $event['id'];
41 $this->_priceSetID
= $this->priceSetCreate();
42 CRM_Price_BAO_PriceSet
::addTo('civicrm_event', $this->_eventId
, $this->_priceSetID
);
43 $priceSet = CRM_Price_BAO_PriceSet
::getSetDetail($this->_priceSetID
, TRUE, FALSE);
44 $priceSet = CRM_Utils_Array
::value($this->_priceSetID
, $priceSet);
45 $this->_feeBlock
= CRM_Utils_Array
::value('fields', $priceSet);
49 * Clean up after test.
51 public function tearDown() {
52 $this->eventDelete($this->_eventId
);
53 $this->quickCleanUpFinancialEntities();
57 * Create an event with a price set.
59 * @todo resolve this with parent function.
64 protected function priceSetCreate($type = 'Radio') {
67 $paramsSet['title'] = 'Two Options' . substr(sha1(rand()), 0, 4);
68 $paramsSet['name'] = CRM_Utils_String
::titleToVar('Two Options') . substr(sha1(rand()), 0, 4);
69 $paramsSet['is_active'] = FALSE;
70 $paramsSet['extends'] = 1;
72 $priceSet = CRM_Price_BAO_PriceSet
::create($paramsSet);
74 if ($type == 'Text') {
76 'label' => 'Text Price Field',
77 'name' => CRM_Utils_String
::titleToVar('text_price_field'),
78 'html_type' => 'Text',
79 'option_label' => array('1' => 'Text Price Field'),
80 'option_name' => array('1' => CRM_Utils_String
::titleToVar('text_price_field')),
81 'option_weight' => array('1' => 1),
82 'option_amount' => array('1' => 10),
83 'option_count' => array(1 => 1),
84 'is_display_amounts' => 1,
86 'options_per_line' => 1,
87 'is_active' => array('1' => 1),
88 'price_set_id' => $priceSet->id
,
90 'financial_type_id' => $this->getFinancialTypeId('Event Fee'),
95 'label' => 'Price Field',
96 'name' => CRM_Utils_String
::titleToVar('Two Options'),
97 'html_type' => 'Radio',
98 //'price' => $feeTotal,
99 'option_label' => array('1' => 'Expensive Room', '2' => "Cheap Room", '3' => 'Very Expensive'),
100 'option_value' => array('1' => 'E', '2' => 'C', '3' => 'V'),
101 'option_name' => array('1' => 'Expensive', '2' => "Cheap", "3" => "Very Expensive"),
102 'option_weight' => array('1' => 1, '2' => 2, '3' => 3),
103 'option_amount' => array('1' => $this->_expensiveFee
, '2' => $this->_cheapFee
, '3' => $this->_veryExpensive
),
104 'option_count' => array(1 => 1, 2 => 1, 3 => 1),
105 'is_display_amounts' => 1,
107 'options_per_line' => 1,
108 'is_active' => array('1' => 1),
109 'price_set_id' => $priceSet->id
,
111 'financial_type_id' => $this->getFinancialTypeId('Event Fee'),
114 $field = CRM_Price_BAO_PriceField
::create($paramsField);
115 $values = $this->callAPISuccess('PriceFieldValue', 'get', [
116 'price_field_id' => $field->id
,
117 'return' => ['id', 'label']
119 foreach ($values['values'] as $value) {
120 switch ($value['label']) {
121 case 'Expensive Room':
122 $this->expensiveFeeValueID
= $value['id'];
126 $this->cheapFeeValueID
= $value['id'];
129 case 'Very Expensive':
130 $this->veryExpensiveFeeValueID
= $value['id'];
135 $this->priceSetFieldID
= $field->id
;
136 return $priceSet->id
;
140 * Get the total for the invoice.
142 * @param int $contributionId
145 private function contributionInvoice($contributionId) {
147 SELECT SUM(line_total) total
148 FROM civicrm_line_item
149 WHERE contribution_id = {$contributionId}";
150 $dao = CRM_Core_DAO
::executeQuery($query);
152 $this->assertTrue($dao->fetch(), "Succeeded retrieving invoicetotal");
157 * Get the total income from the participant record.
159 * @param int $participantId
163 private function totalIncome($participantId) {
165 SELECT SUM(fi.amount) total
166 FROM civicrm_financial_item fi
167 INNER JOIN civicrm_line_item li ON li.id = fi.entity_id AND fi.entity_table = 'civicrm_line_item'
168 WHERE li.entity_table = 'civicrm_participant' AND li.entity_id = ${participantId}
170 $dao = CRM_Core_DAO
::executeQuery($query);
172 $this->assertTrue($dao->fetch(), "Succeeded retrieving total Income");
177 * Check the relevant entity balances.
179 * @param float $amount
181 private function balanceCheck($amount) {
182 $this->assertEquals($amount, $this->contributionInvoice($this->_contributionId
), "Invoice must a total of $amount");
183 $this->assertEquals($amount, $this->totalIncome($this->_participantId
), "The recorded income must be $amount ");
187 * Prepare records for editing.
189 public function registerParticipantAndPay($actualPaidAmt = NULL) {
194 'event_id' => $this->_eventId
,
195 'register_date' => date('Y-m-d') . " 00:00:00",
198 'source' => 'Event_' . $this->_eventId
,
199 'contact_id' => $this->_contactId
,
200 //'fee_level' => CRM_Core_DAO::VALUE_SEPARATOR.'Expensive Room'.CRM_Core_DAO::VALUE_SEPARATOR,
202 $participant = $this->callAPISuccess('Participant', 'create', $params);
203 $this->_participantId
= $participant['id'];
205 $actualPaidAmt = $actualPaidAmt ?
$actualPaidAmt : $this->_expensiveFee
;
207 $contributionParams = array(
208 'total_amount' => $actualPaidAmt,
209 'source' => 'Testset with information',
211 'receipt_date' => date('Y-m-d') . " 00:00:00",
212 'contact_id' => $this->_contactId
,
213 'financial_type_id' => 4,
214 'payment_instrument_id' => 4,
215 'contribution_status_id' => 1,
216 'receive_date' => date('Y-m-d') . " 00:00:00",
218 'partial_payment_total' => $this->_expensiveFee
,
219 'partial_amount_to_pay' => $actualPaidAmt,
222 $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams);
223 $this->_contributionId
= $contribution['id'];
225 $this->callAPISuccess('participant_payment', 'create', array(
226 'participant_id' => $this->_participantId
,
227 'contribution_id' => $this->_contributionId
,
230 $priceSetParams['price_' . $this->priceSetFieldID
] = $this->expensiveFeeValueID
;
232 $lineItems = CRM_Price_BAO_LineItem
::buildLineItemsForSubmittedPriceField($priceSetParams);
233 CRM_Price_BAO_PriceSet
::processAmount($this->_feeBlock
, $priceSetParams, $lineItems);
234 $lineItemVal[$this->_priceSetID
] = $lineItems;
235 CRM_Price_BAO_LineItem
::processPriceSet($participant['id'], $lineItemVal, $this->getContributionObject($contribution['id']), 'civicrm_participant');
236 $this->balanceCheck($this->_expensiveFee
);
239 public function testCRM19273() {
240 $this->registerParticipantAndPay();
242 $priceSetParams['price_' . $this->priceSetFieldID
] = $this->cheapFeeValueID
;
243 $lineItem = CRM_Price_BAO_LineItem
::getLineItems($this->_participantId
, 'participant');
244 CRM_Price_BAO_LineItem
::changeFeeSelections($priceSetParams, $this->_participantId
, 'participant', $this->_contributionId
, $this->_feeBlock
, $lineItem, $this->_expensiveFee
);
245 $this->balanceCheck($this->_cheapFee
);
247 $priceSetParams['price_' . $this->priceSetFieldID
] = $this->expensiveFeeValueID
;
248 $lineItem = CRM_Price_BAO_LineItem
::getLineItems($this->_participantId
, 'participant');
250 CRM_Price_BAO_LineItem
::changeFeeSelections($priceSetParams, $this->_participantId
, 'participant', $this->_contributionId
, $this->_feeBlock
, $lineItem, $this->_expensiveFee
);
252 $this->balanceCheck($this->_expensiveFee
);
254 $priceSetParams['price_' . $this->priceSetFieldID
] = $this->veryExpensiveFeeValueID
;
255 $lineItem = CRM_Price_BAO_LineItem
::getLineItems($this->_participantId
, 'participant');
256 CRM_Price_BAO_LineItem
::changeFeeSelections($priceSetParams, $this->_participantId
, 'participant', $this->_contributionId
, $this->_feeBlock
, $lineItem, $this->_expensiveFee
);
257 $this->balanceCheck($this->_veryExpensive
);
261 * 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
263 public function testCRM21245() {
264 $this->registerParticipantAndPay(50);
265 $partiallyPaidContribuitonStatus = CRM_Core_PseudoConstant
::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Partially paid');
266 $this->assertEquals($this->callAPISuccessGetValue('Contribution', array('id' => $this->_contributionId
, 'return' => 'contribution_status_id')), $partiallyPaidContribuitonStatus);
268 $priceSetParams['price_' . $this->priceSetFieldID
] = $this->veryExpensiveFeeValueID
;
269 $lineItem = CRM_Price_BAO_LineItem
::getLineItems($this->_participantId
, 'participant');
270 CRM_Price_BAO_LineItem
::changeFeeSelections($priceSetParams, $this->_participantId
, 'participant', $this->_contributionId
, $this->_feeBlock
, $lineItem);
271 $this->assertEquals($this->callAPISuccessGetValue('Contribution', array('id' => $this->_contributionId
, 'return' => 'contribution_status_id')), $partiallyPaidContribuitonStatus);
275 * Test that proper financial items are recorded for cancelled line items
277 public function testCRM20611() {
278 $this->registerParticipantAndPay();
279 $priceSetParams['price_' . $this->priceSetFieldID
] = $this->expensiveFeeValueID
;
280 $lineItem = CRM_Price_BAO_LineItem
::getLineItems($this->participantID
, 'participant');
281 CRM_Price_BAO_LineItem
::changeFeeSelections($priceSetParams, $this->_participantId
, 'participant', $this->_contributionId
, $this->_feeBlock
, $lineItem);
282 $this->balanceCheck($this->_expensiveFee
);
284 $priceSetParams['price_' . $this->priceSetFieldID
] = $this->cheapFeeValueID
;
285 $lineItem = CRM_Price_BAO_LineItem
::getLineItems($this->participantID
, 'participant');
286 CRM_Price_BAO_LineItem
::changeFeeSelections($priceSetParams, $this->_participantId
, 'participant', $this->_contributionId
, $this->_feeBlock
, $lineItem);
287 $this->balanceCheck($this->_cheapFee
);
289 //Complete the refund payment.
290 $submittedValues = array(
291 'total_amount' => 120,
292 'payment_instrument_id' => 3,
294 CRM_Contribute_BAO_Contribution
::recordAdditionalPayment($this->_contributionId
, $submittedValues, 'refund', $this->_participantId
);
296 // retrieve the cancelled line-item information
297 $cancelledLineItem = $this->callAPISuccessGetSingle('LineItem', array(
298 'entity_table' => 'civicrm_participant',
299 'entity_id' => $this->_participantId
,
302 // retrieve the related financial lin-items
303 $financialItems = $this->callAPISuccess('FinancialItem', 'Get', array(
304 'entity_id' => $cancelledLineItem['id'],
305 'entity_table' => 'civicrm_line_item',
307 $this->assertEquals($financialItems['count'], 2, 'Financial Items for Cancelled fee is not proper');
309 $contributionCompletedStatusID = CRM_Core_PseudoConstant
::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
310 $expectedAmount = 100.00;
311 foreach ($financialItems['values'] as $id => $financialItem) {
312 $this->assertEquals($expectedAmount, $financialItem['amount']);
313 $this->assertNotEmpty($financialItem['financial_account_id']);
314 $this->assertEquals($contributionCompletedStatusID, $financialItem['status_id']);
315 $expectedAmount = -$expectedAmount;
320 * Test to ensure that correct financial records are entered on text price field fee change on event registration
322 public function testCRM21513() {
323 $this->_priceSetID
= $this->priceSetCreate('Text');
324 CRM_Price_BAO_PriceSet
::addTo('civicrm_event', $this->_eventId
, $this->_priceSetID
);
325 $priceSet = CRM_Price_BAO_PriceSet
::getSetDetail($this->_priceSetID
, TRUE, FALSE);
326 $priceSet = CRM_Utils_Array
::value($this->_priceSetID
, $priceSet);
327 $this->_feeBlock
= CRM_Utils_Array
::value('fields', $priceSet);
333 'event_id' => $this->_eventId
,
334 'register_date' => date('Y-m-d') . " 00:00:00",
337 'source' => 'Event_' . $this->_eventId
,
338 'contact_id' => $this->_contactId
,
340 $participant = $this->callAPISuccess('Participant', 'create', $params);
341 $this->_participantId
= $participant['id'];
342 $contributionParams = array(
343 'total_amount' => 10,
344 'source' => 'Testset with information',
346 'receipt_date' => date('Y-m-d') . " 00:00:00",
347 'contact_id' => $this->_contactId
,
348 'financial_type_id' => 4,
349 'payment_instrument_id' => 4,
350 'contribution_status_id' => CRM_Core_PseudoConstant
::getKey('CRM_Contribute_DAO_Contribution', 'contribution_status_id', 'Pending'),
351 'receive_date' => date('Y-m-d') . " 00:00:00",
355 $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams);
356 $this->_contributionId
= $contribution['id'];
358 $this->callAPISuccess('participant_payment', 'create', array(
359 'participant_id' => $this->_participantId
,
360 'contribution_id' => $this->_contributionId
,
363 // CASE 1: Choose text price qty 1 (x$10 = $10 amount)
364 $priceSetParams['price_' . $this->priceSetFieldID
] = 1;
365 $lineItem = CRM_Price_BAO_LineItem
::getLineItems($this->_participantId
, 'participant');
366 CRM_Price_BAO_PriceSet
::processAmount($this->_feeBlock
, $priceSetParams, $lineItem);
367 $lineItemVal[$this->_priceSetID
] = $lineItem;
368 CRM_Price_BAO_LineItem
::processPriceSet($this->_participantId
, $lineItemVal, $this->getContributionObject($contribution['id']), 'civicrm_participant');
370 // CASE 2: Choose text price qty 3 (x$10 = $30 amount)
371 $priceSetParams['price_' . $this->priceSetFieldID
] = 3;
372 $lineItem = CRM_Price_BAO_LineItem
::getLineItems($participant['id'], 'participant');
373 CRM_Price_BAO_LineItem
::changeFeeSelections($priceSetParams, $participant['id'], 'participant', $this->_contributionId
, $this->_feeBlock
, $lineItem, 0);
375 // CASE 3: Choose text price qty 2 (x$10 = $20 amount)
376 $priceSetParams['price_' . $this->priceSetFieldID
] = 2;
377 $lineItem = CRM_Price_BAO_LineItem
::getLineItems($participant['id'], 'participant');
378 CRM_Price_BAO_LineItem
::changeFeeSelections($priceSetParams, $participant['id'], 'participant', $this->_contributionId
, $this->_feeBlock
, $lineItem, 0);
380 $financialItems = $this->callAPISuccess('FinancialItem', 'Get', array(
381 'entity_table' => 'civicrm_line_item',
382 'entity_id' => array('IN' => array_keys($lineItem)),
386 $unpaidStatus = CRM_Core_PseudoConstant
::getKey('CRM_Financial_DAO_FinancialItem', 'status_id', 'Unpaid');
387 $expectedResults = array(
389 'amount' => 10.00, // when qty 1 is used
390 'status_id' => $unpaidStatus,
391 'entity_table' => 'civicrm_line_item',
395 'amount' => 20.00, // when qty 3 is used, add the surplus amount i.e. $30 - $10 = $20
396 'status_id' => $unpaidStatus,
397 'entity_table' => 'civicrm_line_item',
401 'amount' => -10.00, // when qty 2 is used, add the surplus amount i.e. $20 - $30 = -$10
402 'status_id' => $unpaidStatus,
403 'entity_table' => 'civicrm_line_item',
407 // Check if 3 financial items were recorded
408 $this->assertEquals(count($expectedResults), $financialItems['count']);
409 foreach ($expectedResults as $key => $expectedResult) {
410 foreach ($expectedResult as $column => $value) {
411 $this->assertEquals($expectedResult[$column], $financialItems['values'][$key][$column]);
415 $this->balanceCheck(20);
419 * CRM-17151: Test that Contribution status change to 'Completed' if balance is zero.
421 public function testCRM17151() {
422 $this->registerParticipantAndPay();
424 $contributionStatuses = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
425 $partiallyPaidStatusId = array_search('Partially paid', $contributionStatuses);
426 $pendingRefundStatusId = array_search('Pending refund', $contributionStatuses);
427 $completedStatusId = array_search('Completed', $contributionStatuses);
428 $this->assertDBCompareValue('CRM_Contribute_BAO_Contribution', $this->_contributionId
, 'contribution_status_id', 'id', $completedStatusId, 'Payment t be completed');
429 $priceSetParams['price_' . $this->priceSetFieldID
] = $this->cheapFeeValueID
;
430 $lineItem = CRM_Price_BAO_LineItem
::getLineItems($this->_participantId
, 'participant');
431 CRM_Price_BAO_LineItem
::changeFeeSelections($priceSetParams, $this->_participantId
, 'participant', $this->_contributionId
, $this->_feeBlock
, $lineItem);
432 $this->assertDBCompareValue('CRM_Contribute_BAO_Contribution', $this->_contributionId
, 'contribution_status_id', 'id', $pendingRefundStatusId, 'Contribution must be refunding');
433 $priceSetParams['price_' . $this->priceSetFieldID
] = $this->expensiveFeeValueID
;
434 $lineItem = CRM_Price_BAO_LineItem
::getLineItems($this->_participantId
, 'participant');
435 CRM_Price_BAO_LineItem
::changeFeeSelections($priceSetParams, $this->_participantId
, 'participant', $this->_contributionId
, $this->_feeBlock
, $lineItem);
436 $this->assertDBCompareValue('CRM_Contribute_BAO_Contribution', $this->_contributionId
, 'contribution_status_id', 'id', $completedStatusId, 'Contribution must, after complete payment be in state completed');
437 $priceSetParams['price_' . $this->priceSetFieldID
] = $this->veryExpensiveFeeValueID
;
438 $lineItem = CRM_Price_BAO_LineItem
::getLineItems($this->_participantId
, 'participant');
439 CRM_Price_BAO_LineItem
::changeFeeSelections($priceSetParams, $this->_participantId
, 'participant', $this->_contributionId
, $this->_feeBlock
, $lineItem);
440 $this->assertDBCompareValue('CRM_Contribute_BAO_Contribution', $this->_contributionId
, 'contribution_status_id', 'id', $partiallyPaidStatusId, 'Partial Paid');