CRM-20611: fix financial records of cancelled line-items on event fee change selection
[civicrm-core.git] / tests / phpunit / CRM / Event / BAO / CRM19273Test.php
CommitLineData
0ae57b4c
KE
1<?php
2/**
3 * Class CRM_Event_BAO_AdditionalPaymentTest
4 * @group headless
5 */
6class CRM_Event_BAO_CRM19273 extends CiviUnitTestCase {
7
8 protected $_priceSetID;
9 protected $_cheapFee = 80;
10 protected $_expensiveFee = 100;
11 protected $_veryExpensive = 120;
12
13 /**
14 * @var int
15 */
16 protected $contributionID;
17
18 /**
19 * @var int
20 */
21 protected $participantID;
22
23 /**
24 * Price set field id.
25 *
26 * @var int
27 */
28 protected $priceSetFieldID;
29
30 /**
31 * Set up for test.
32 */
33 public function setUp() {
34 parent::setUp();
35 $this->cleanup();
36 $this->_contactId = $this->individualCreate();
37 $event = $this->eventCreate(array('is_monetary' => 1));
38 $this->_eventId = $event['id'];
39 $this->_priceSetID = $this->eventPriceSetCreate();
40 CRM_Price_BAO_PriceSet::addTo('civicrm_event', $this->_eventId, $this->_priceSetID);
41 $priceSet = CRM_Price_BAO_PriceSet::getSetDetail($this->_priceSetID, TRUE, FALSE);
42 $priceSet = CRM_Utils_Array::value($this->_priceSetID, $priceSet);
43 $this->_feeBlock = CRM_Utils_Array::value('fields', $priceSet);
44 $this->registerParticipantAndPay();
45 }
46
47 /**
48 * Clean up after test.
49 */
50 public function tearDown() {
51 $this->eventDelete($this->_eventId);
52 $this->quickCleanUpFinancialEntities();
53 }
54
55
56 /**
57 * Remove default price field stuff.
58 *
59 * This is not actually good. However resolving this requires
60 * a lot more fixes & we have a bit of work to do on event tests.
61 *
62 * @throws \Exception
63 */
64 protected function cleanup() {
65 $this->quickCleanup(
66 array(
67 'civicrm_price_field_value',
68 'civicrm_price_field',
69 'civicrm_price_set',
70 )
71 );
72 }
73
74 /**
75 * Create an event with a price set.
76 *
77 * @todo resolve this with parent function.
78 *
79 * @param int $amount
80 * @param int $min_fee
81 * @return int
82 */
83 protected function eventPriceSetCreate($amount = 0, $min_fee = 0) {
84
85 $paramsSet['title'] = 'Two Options';
86 $paramsSet['name'] = CRM_Utils_String::titleToVar('Two Options');
87 $paramsSet['is_active'] = FALSE;
88 $paramsSet['extends'] = 1;
89
90 $priceSet = CRM_Price_BAO_PriceSet::create($paramsSet);
91
92 $paramsField = array(
93 'label' => 'Price Field',
94 'name' => CRM_Utils_String::titleToVar('Two Options'),
95 'html_type' => 'Radio',
96 //'price' => $feeTotal,
97 'option_label' => array('1' => 'Expensive Room', '2' => "Cheap Room", '3' => 'Very Expensive'),
98 'option_value' => array('1' => 'E', '2' => 'C', '3' => 'V'),
99 'option_name' => array('1' => 'Expensive', '2' => "Cheap", "3" => "Very Expensive"),
100 'option_weight' => array('1' => 1, '2' => 2, '3' => 3),
101 'option_amount' => array('1' => $this->_expensiveFee, '2' => $this->_cheapFee, '3' => $this->_veryExpensive),
102 'is_display_amounts' => 1,
103 'weight' => 1,
104 'options_per_line' => 1,
105 'is_active' => array('1' => 1),
106 'price_set_id' => $priceSet->id,
107 'is_enter_qty' => 1,
108 'financial_type_id' => $this->getFinancialTypeId('Event Fee'),
109 );
110 $field = CRM_Price_BAO_PriceField::create($paramsField);
111 $this->priceSetFieldID = $field->id;
112 return $priceSet->id;
113 }
114
115 /**
116 * Get the total for the invoice.
117 *
118 * @param int $contributionId
119 * @return mixed
120 */
121 private function contributionInvoice($contributionId) {
122
123 $query = "
124 SELECT SUM(line_total) total
125 FROM civicrm_line_item
126 WHERE entity_table = 'civicrm_participant'
127 AND entity_id = {$contributionId}";
128 $dao = CRM_Core_DAO::executeQuery($query);
129
130 $this->assertTrue($dao->fetch(), "Succeeded retrieving invoicetotal");
131 return $dao->total;
132 }
133
134 /**
135 * Get the total income from the participant record.
136 *
137 * @param int $participantId
138 *
139 * @return mixed
140 */
141 private function totalIncome($participantId) {
142
143 // @todo use INNER JOINS, this is not our style.
144 $query = "
145 SELECT SUM(et.amount) total
146 FROM civicrm_entity_financial_trxn et
147 , civicrm_financial_item fi
148 , civicrm_line_item li
149 WHERE et.entity_table='civicrm_financial_item'
150 AND fi.id = et.entity_id
151 AND fi.entity_table='civicrm_line_item'
152 AND fi.entity_id = li.id
153 AND li.entity_table = 'civicrm_participant'
154 AND li.entity_id = ${participantId}
155 ";
156 $dao = CRM_Core_DAO::executeQuery($query);
157
158 $this->assertTrue($dao->fetch(), "Succeeded retrieving total Income");
159 return $dao->total;
160 }
161
162 /**
163 * Check the relevant entity balances.
164 *
165 * @param float $amount
166 */
167 private function balanceCheck($amount) {
168 $this->assertEquals($this->contributionInvoice($this->contributionID), $amount, "Invoice must a total of $amount");
169 $this->assertEquals($this->totalIncome($this->participantID), $amount, "The recorded income must be $amount ");
170 $this->assertEquals($this->totalIncome($this->contributionID), $amount, "The accumulated assets must be $amount ");
171 }
172
173 /**
174 * Prepare records for editing.
175 */
176 public function registerParticipantAndPay() {
177 $params = array(
178 'send_receipt' => 1,
179 'is_test' => 0,
180 'is_pay_later' => 0,
181 'event_id' => $this->_eventId,
182 'register_date' => date('Y-m-d') . " 00:00:00",
183 'role_id' => 1,
184 'status_id' => 1,
185 'source' => 'Event_' . $this->_eventId,
186 'contact_id' => $this->_contactId,
187 //'fee_level' => CRM_Core_DAO::VALUE_SEPARATOR.'Expensive Room'.CRM_Core_DAO::VALUE_SEPARATOR,
188 );
189 $participant = $this->callAPISuccess('Participant', 'create', $params);
190 $this->_participantId = $participant['id'];
191
192 $actualPaidAmt = $this->_expensiveFee;
193
194 $contributionParams = array(
195 'total_amount' => $actualPaidAmt,
196 'source' => 'Testset with information',
197 'currency' => 'USD',
198 'non_deductible_amount' => 'null',
199 'receipt_date' => date('Y-m-d') . " 00:00:00",
200 'contact_id' => $this->_contactId,
201 'financial_type_id' => 4,
202 'payment_instrument_id' => 4,
203 'contribution_status_id' => 1,
204 'receive_date' => date('Y-m-d') . " 00:00:00",
205 'skipLineItem' => 1,
206 'partial_payment_total' => $this->_expensiveFee,
207 'partial_amount_pay' => $actualPaidAmt,
208 );
209
210 $contribution = CRM_Contribute_BAO_Contribution::create($contributionParams);
211 $this->_contributionId = $contribution->id;
212
213 $this->callAPISuccess('participant_payment', 'create', array(
214 'participant_id' => $this->_participantId,
215 'contribution_id' => $this->_contributionId,
216 ));
217
218 $PSparams['price_1'] = 1; // 1 is the option of the expensive room
219 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_participantId, 'participant');
220 CRM_Price_BAO_PriceSet::processAmount($this->_feeBlock, $PSparams, $lineItem);
221 $lineItemVal[$this->_priceSetID] = $lineItem;
222 CRM_Price_BAO_LineItem::processPriceSet($participant['id'], $lineItemVal, $contribution, 'civicrm_participant');
223
224 $this->contributionID = $this->callAPISuccessGetValue('Contribution', array('return' => 'id'));
225 $this->participantID = $this->callAPISuccessGetValue('Participant', array('return' => 'id'));
226 $this->balanceCheck($this->_expensiveFee);
227 }
228
229 public function testCRM19273() {
230
231 $PSparams['price_1'] = 2;
232 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->participantID, 'participant');
233 CRM_Event_BAO_Participant::changeFeeSelections($PSparams, $this->participantID, $this->_contributionId, $this->_feeBlock, $lineItem, $this->_expensiveFee, $this->_priceSetID);
234 $this->balanceCheck($this->_cheapFee);
235
236 $PSparams['price_1'] = 1;
237 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->participantID, 'participant');
238 CRM_Event_BAO_Participant::changeFeeSelections($PSparams, $this->participantID, $this->_contributionId, $this->_feeBlock, $lineItem, $this->_expensiveFee, $this->_priceSetID);
239 $this->balanceCheck($this->_expensiveFee);
240
241 $PSparams['price_1'] = 3;
242 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->participantID, 'participant');
243
244 CRM_Event_BAO_Participant::changeFeeSelections($PSparams, $this->participantID, $this->_contributionId, $this->_feeBlock, $lineItem, $this->_expensiveFee, $this->_priceSetID);
245 $this->balanceCheck($this->_veryExpensive);
aa84923f 246
247 }
248
249 /**
250 * Test that proper financial items are recorded for cancelled line items
251 */
252 public function testCRM20611() {
253 $PSparams['price_1'] = 1;
254 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->participantID, 'participant');
255 CRM_Event_BAO_Participant::changeFeeSelections($PSparams, $this->participantID, $this->_contributionId, $this->_feeBlock, $lineItem, $this->_expensiveFee, $this->_priceSetID);
256 $this->balanceCheck($this->_expensiveFee);
257
258 $PSparams['price_1'] = 2;
259 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->participantID, 'participant');
260 CRM_Event_BAO_Participant::changeFeeSelections($PSparams, $this->participantID, $this->_contributionId, $this->_feeBlock, $lineItem, $this->_expensiveFee, $this->_priceSetID);
261 $this->balanceCheck($this->_cheapFee);
262
263 //Complete the refund payment.
264 $submittedValues = array(
265 'total_amount' => 120,
266 'payment_instrument_id' => 3,
267 );
268 CRM_Contribute_BAO_Contribution::recordAdditionalPayment($this->_contributionId, $submittedValues, 'refund', $this->participantID);
269
270 // retrieve the cancelled line-item information
271 $cancelledLineItem = $this->callAPISuccessGetSingle('LineItem', array(
272 'entity_table' => 'civicrm_participant',
273 'entity_id' => $this->participantID,
274 'qty' => 0,
275 ));
276 // retrieve the related financial lin-items
277 $financialItems = $this->callAPISuccess('FinancialItem', 'Get', array(
278 'entity_id' => $cancelledLineItem['id'],
279 'entity_table' => 'civicrm_line_item',
280 ));
281 $this->assertEquals($financialItems['count'], 2, 'Financial Items for Cancelled fee is not proper');
282
283 $contributionCompletedStatusID = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
284 $expectedAmount = 100.00;
285 foreach ($financialItems['values'] as $id => $financialItem) {
286 $this->assertEquals($expectedAmount, $financialItem['amount']);
287 $this->assertNotEmpty($financialItem['financial_account_id']);
288 $this->assertEquals($contributionCompletedStatusID, $financialItem['status_id']);
289 $expectedAmount = -$expectedAmount;
290 }
0ae57b4c
KE
291 }
292
293}