Commit | Line | Data |
---|---|---|
b7f554fe E |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
7d61e75f | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
b7f554fe | 5 | | | |
7d61e75f TO |
6 | | This work is published under the GNU AGPLv3 license with some | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
b7f554fe E |
9 | +--------------------------------------------------------------------+ |
10 | */ | |
11 | ||
b7f554fe E |
12 | /** |
13 | * Test APIv3 civicrm_contribute_* functions | |
14 | * | |
15 | * @package CiviCRM_APIv3 | |
16 | * @subpackage API_Contribution | |
acb109b7 | 17 | * @group headless |
b7f554fe E |
18 | */ |
19 | class api_v3_PaymentTest extends CiviUnitTestCase { | |
20 | ||
b7f554fe | 21 | protected $_individualId; |
d3b3ad06 | 22 | |
b7f554fe | 23 | protected $_financialTypeId = 1; |
d3b3ad06 | 24 | |
b7f554fe E |
25 | /** |
26 | * Setup function. | |
3d4f6f65 | 27 | * |
28 | * @throws \CRM_Core_Exception | |
b7f554fe E |
29 | */ |
30 | public function setUp() { | |
31 | parent::setUp(); | |
32 | ||
33 | $this->_apiversion = 3; | |
34 | $this->_individualId = $this->individualCreate(); | |
d3b3ad06 | 35 | CRM_Core_Config::singleton()->userPermissionClass->permissions = []; |
b7f554fe E |
36 | } |
37 | ||
38 | /** | |
39 | * Clean up after each test. | |
fda18dc3 | 40 | * |
41 | * @throws \Exception | |
b7f554fe E |
42 | */ |
43 | public function tearDown() { | |
44 | $this->quickCleanUpFinancialEntities(); | |
d3b3ad06 | 45 | $this->quickCleanup(['civicrm_uf_match']); |
eba13f6d | 46 | unset(CRM_Core_Config::singleton()->userPermissionClass->permissions); |
fda18dc3 | 47 | parent::tearDown(); |
b7f554fe E |
48 | } |
49 | ||
50 | /** | |
52873538 | 51 | * Test Get Payment api. |
3d4f6f65 | 52 | * |
53 | * @throws \CRM_Core_Exception | |
b7f554fe E |
54 | */ |
55 | public function testGetPayment() { | |
d3b3ad06 | 56 | $p = [ |
b7f554fe E |
57 | 'contact_id' => $this->_individualId, |
58 | 'receive_date' => '2010-01-20', | |
59 | 'total_amount' => 100.00, | |
60 | 'financial_type_id' => $this->_financialTypeId, | |
61 | 'trxn_id' => 23456, | |
62 | 'contribution_status_id' => 1, | |
d3b3ad06 | 63 | ]; |
b7f554fe E |
64 | $contribution = $this->callAPISuccess('contribution', 'create', $p); |
65 | ||
d3b3ad06 | 66 | $params = [ |
b7f554fe | 67 | 'contribution_id' => $contribution['id'], |
979748a2 | 68 | 'check_permissions' => TRUE, |
d3b3ad06 | 69 | ]; |
70 | CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'administer CiviCRM']; | |
d2aeabca | 71 | $this->callAPIFailure('payment', 'get', $params, 'API permission check failed for Payment/get call; insufficient permission: require access CiviCRM and access CiviContribute'); |
b7f554fe | 72 | |
979748a2 | 73 | array_push(CRM_Core_Config::singleton()->userPermissionClass->permissions, 'access CiviContribute'); |
d2aeabca | 74 | $this->callAPISuccess('payment', 'get', $params); |
b7f554fe | 75 | |
979748a2 | 76 | $payment = $this->callAPIAndDocument('payment', 'get', $params, __FUNCTION__, __FILE__); |
b7f554fe | 77 | $this->assertEquals(1, $payment['count']); |
979748a2 | 78 | |
d3b3ad06 | 79 | $expectedResult = [ |
80 | $contribution['id'] => [ | |
c60d3584 PN |
81 | 'total_amount' => 100, |
82 | 'trxn_id' => 23456, | |
83 | 'trxn_date' => '2010-01-20 00:00:00', | |
84 | 'contribution_id' => $contribution['id'], | |
85 | 'is_payment' => 1, | |
d3b3ad06 | 86 | ], |
87 | ]; | |
a44499b4 | 88 | $this->checkPaymentResult($payment, $expectedResult); |
d3b3ad06 | 89 | $this->callAPISuccess('Contribution', 'Delete', [ |
b7f554fe | 90 | 'id' => $contribution['id'], |
d3b3ad06 | 91 | ]); |
3d4f6f65 | 92 | $this->validateAllPayments(); |
b7f554fe E |
93 | } |
94 | ||
d2aeabca MW |
95 | /** |
96 | * Test multiple payments for contribution and assert if option | |
97 | * and is_payment returns the correct list of payments. | |
98 | * | |
99 | * @throws \CRM_Core_Exception | |
100 | */ | |
101 | public function testMultiplePaymentsForContribution() { | |
102 | $params = [ | |
103 | 'contact_id' => $this->_individualId, | |
104 | 'total_amount' => 100, | |
105 | 'contribution_status_id' => 'Pending', | |
106 | ]; | |
107 | $contributionID = $this->contributionCreate($params); | |
108 | $paymentParams = [ | |
109 | 'contribution_id' => $contributionID, | |
110 | 'total_amount' => 20, | |
111 | 'trxn_date' => date('Y-m-d'), | |
112 | ]; | |
113 | $this->callAPISuccess('payment', 'create', $paymentParams); | |
114 | $paymentParams['total_amount'] = 30; | |
115 | $this->callAPISuccess('payment', 'create', $paymentParams); | |
116 | ||
117 | $paymentParams['total_amount'] = 50; | |
118 | $this->callAPISuccess('payment', 'create', $paymentParams); | |
119 | ||
120 | //check if contribution status is set to "Completed". | |
121 | $contribution = $this->callAPISuccessGetSingle('Contribution', [ | |
122 | 'id' => $contributionID, | |
123 | ]); | |
124 | $this->assertEquals('Completed', $contribution['contribution_status']); | |
125 | ||
126 | //Get Payment using options | |
127 | $getParams = [ | |
128 | 'sequential' => 1, | |
129 | 'contribution_id' => $contributionID, | |
130 | 'is_payment' => 1, | |
131 | 'options' => ['limit' => 0, 'sort' => 'total_amount DESC'], | |
132 | ]; | |
133 | $payments = $this->callAPISuccess('Payment', 'get', $getParams); | |
134 | $this->assertEquals(3, $payments['count']); | |
135 | foreach ([50, 30, 20] as $key => $total_amount) { | |
136 | $this->assertEquals($total_amount, $payments['values'][$key]['total_amount']); | |
137 | } | |
138 | } | |
139 | ||
6045f2b7 JP |
140 | /** |
141 | * Retrieve Payment using trxn_id. | |
3d4f6f65 | 142 | * |
143 | * @throws \CRM_Core_Exception | |
6045f2b7 JP |
144 | */ |
145 | public function testGetPaymentWithTrxnID() { | |
146 | $this->_individualId2 = $this->individualCreate(); | |
147 | $params1 = [ | |
148 | 'contact_id' => $this->_individualId, | |
149 | 'trxn_id' => 111111, | |
150 | 'total_amount' => 10, | |
151 | ]; | |
152 | $contributionID1 = $this->contributionCreate($params1); | |
153 | ||
154 | $params2 = [ | |
155 | 'contact_id' => $this->_individualId2, | |
156 | 'trxn_id' => 222222, | |
157 | 'total_amount' => 20, | |
158 | ]; | |
159 | $contributionID2 = $this->contributionCreate($params2); | |
160 | ||
161 | $paymentParams = ['trxn_id' => 111111]; | |
162 | $payment = $this->callAPISuccess('payment', 'get', $paymentParams); | |
163 | $expectedResult = [ | |
164 | $payment['id'] => [ | |
165 | 'total_amount' => 10, | |
166 | 'trxn_id' => 111111, | |
167 | 'status_id' => 1, | |
168 | 'is_payment' => 1, | |
169 | 'contribution_id' => $contributionID1, | |
170 | ], | |
171 | ]; | |
172 | $this->checkPaymentResult($payment, $expectedResult); | |
173 | ||
174 | $paymentParams = ['trxn_id' => 222222]; | |
175 | $payment = $this->callAPISuccess('payment', 'get', $paymentParams); | |
176 | $expectedResult = [ | |
177 | $payment['id'] => [ | |
178 | 'total_amount' => 20, | |
179 | 'trxn_id' => 222222, | |
180 | 'status_id' => 1, | |
181 | 'is_payment' => 1, | |
182 | 'contribution_id' => $contributionID2, | |
183 | ], | |
184 | ]; | |
185 | $this->checkPaymentResult($payment, $expectedResult); | |
3d4f6f65 | 186 | $this->validateAllPayments(); |
6045f2b7 JP |
187 | } |
188 | ||
a79d2ec2 | 189 | /** |
190 | * Test email receipt for partial payment. | |
3d4f6f65 | 191 | * |
192 | * @throws \CRM_Core_Exception | |
a79d2ec2 | 193 | */ |
194 | public function testPaymentEmailReceipt() { | |
195 | $mut = new CiviMailUtils($this); | |
5266bd48 | 196 | $contribution = $this->createPartiallyPaidParticipantOrder(); |
0fad34a0 | 197 | $event = $this->callAPISuccess('Event', 'get', []); |
198 | $this->addLocationToEvent($event['id']); | |
b5a442ed | 199 | $params = [ |
a79d2ec2 | 200 | 'contribution_id' => $contribution['id'], |
201 | 'total_amount' => 50, | |
434546ac | 202 | 'check_number' => '345', |
203 | 'trxn_date' => '2018-08-13 17:57:56', | |
b5a442ed | 204 | ]; |
a79d2ec2 | 205 | $payment = $this->callAPISuccess('payment', 'create', $params); |
206 | $this->checkPaymentResult($payment, [ | |
207 | $payment['id'] => [ | |
208 | 'from_financial_account_id' => 7, | |
209 | 'to_financial_account_id' => 6, | |
210 | 'total_amount' => 50, | |
211 | 'status_id' => 1, | |
212 | 'is_payment' => 1, | |
213 | ], | |
214 | ]); | |
215 | ||
216 | $this->callAPISuccess('Payment', 'sendconfirmation', ['id' => $payment['id']]); | |
694cfde6 | 217 | $mut->assertSubjects(['Payment Receipt - Annual CiviCRM meet - Mr. Anthony Anderson II']); |
d3b3ad06 | 218 | $mut->checkMailLog([ |
44a2f017 | 219 | 'From: "FIXME" <info@EXAMPLE.ORG>', |
1e477c5b | 220 | 'Dear Anthony,', |
1f6479af | 221 | 'Total Fee: $ 300.00', |
a79d2ec2 | 222 | 'This Payment Amount: $ 50.00', |
39b959db SL |
223 | //150 was paid in the 1st payment. |
224 | 'Balance Owed: $ 100.00', | |
a79d2ec2 | 225 | 'Event Information and Location', |
434546ac | 226 | 'Paid By: Check', |
227 | 'Check Number: 345', | |
228 | 'Transaction Date: August 13th, 2018 5:57 PM', | |
0fad34a0 | 229 | 'event place', |
230 | 'streety street', | |
d3b3ad06 | 231 | ]); |
a79d2ec2 | 232 | $mut->stop(); |
a7b9128b | 233 | $mut->clearMessages(); |
3d4f6f65 | 234 | $this->validateAllPayments(); |
a79d2ec2 | 235 | } |
236 | ||
00ef9b01 | 237 | /** |
238 | * Test email receipt for partial payment. | |
1e0f58c7 | 239 | * |
240 | * @throws \CRM_Core_Exception | |
00ef9b01 | 241 | */ |
242 | public function testPaymentEmailReceiptFullyPaid() { | |
243 | $mut = new CiviMailUtils($this); | |
44a2f017 | 244 | CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviContribute', 'edit contributions', 'access CiviCRM']; |
5266bd48 | 245 | $contribution = $this->createPartiallyPaidParticipantOrder(); |
00ef9b01 | 246 | |
247 | $params = [ | |
248 | 'contribution_id' => $contribution['id'], | |
249 | 'total_amount' => 150, | |
250 | ]; | |
251 | $payment = $this->callAPISuccess('payment', 'create', $params); | |
252 | ||
44a2f017 | 253 | // Here we set the email to an invalid email & use check_permissions, domain email should be used. |
254 | $email = $this->callAPISuccess('Email', 'create', ['contact_id' => 1, 'email' => 'bob@example.com']); | |
255 | $this->callAPISuccess('Payment', 'sendconfirmation', ['id' => $payment['id'], 'from' => $email['id'], 'check_permissions' => 1]); | |
694cfde6 | 256 | $mut->assertSubjects(['Payment Receipt - Annual CiviCRM meet - Mr. Anthony Anderson II', 'Registration Confirmation - Annual CiviCRM meet - Mr. Anthony Anderson II']); |
d3b3ad06 | 257 | $mut->checkMailLog([ |
44a2f017 | 258 | 'From: "FIXME" <info@EXAMPLE.ORG>', |
1e477c5b | 259 | 'Dear Anthony,', |
84060348 | 260 | 'Below you will find a receipt for this payment.', |
1f6479af | 261 | 'Total Fee: $ 300.00', |
00ef9b01 | 262 | 'This Payment Amount: $ 150.00', |
263 | 'Balance Owed: $ 0.00', | |
12ff7379 | 264 | 'Thank you for completing this payment.', |
d3b3ad06 | 265 | ]); |
00ef9b01 | 266 | $mut->stop(); |
267 | $mut->clearMessages(); | |
3d4f6f65 | 268 | $this->validateAllPayments(); |
00ef9b01 | 269 | } |
270 | ||
b5a442ed | 271 | /** |
272 | * Test email receipt for partial payment. | |
a7b9128b | 273 | * |
274 | * @dataProvider getThousandSeparators | |
275 | * | |
276 | * @param string $thousandSeparator | |
3d4f6f65 | 277 | * |
278 | * @throws \CRM_Core_Exception | |
b5a442ed | 279 | */ |
a7b9128b | 280 | public function testRefundEmailReceipt($thousandSeparator) { |
281 | $this->setCurrencySeparators($thousandSeparator); | |
282 | $decimalSeparator = ($thousandSeparator === ',' ? '.' : ','); | |
b5a442ed | 283 | $mut = new CiviMailUtils($this); |
5266bd48 | 284 | $contribution = $this->createPartiallyPaidParticipantOrder(); |
b5a442ed | 285 | $this->callAPISuccess('payment', 'create', [ |
286 | 'contribution_id' => $contribution['id'], | |
287 | 'total_amount' => 50, | |
288 | 'check_number' => '345', | |
289 | 'trxn_date' => '2018-08-13 17:57:56', | |
290 | ]); | |
291 | ||
292 | $payment = $this->callAPISuccess('payment', 'create', [ | |
293 | 'contribution_id' => $contribution['id'], | |
294 | 'total_amount' => -30, | |
295 | 'trxn_date' => '2018-11-13 12:01:56', | |
52746f6a | 296 | 'sequential' => TRUE, |
297 | ])['values'][0]; | |
b5a442ed | 298 | |
52746f6a | 299 | $expected = [ |
300 | 'from_financial_account_id' => 7, | |
301 | 'to_financial_account_id' => 6, | |
302 | 'total_amount' => -30, | |
2561fc11 | 303 | 'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_FinancialTrxn', 'status_id', 'Refunded'), |
52746f6a | 304 | 'is_payment' => 1, |
305 | ]; | |
306 | foreach ($expected as $key => $value) { | |
307 | $this->assertEquals($expected[$key], $payment[$key], 'mismatch on key ' . $key); | |
308 | } | |
b5a442ed | 309 | |
310 | $this->callAPISuccess('Payment', 'sendconfirmation', ['id' => $payment['id']]); | |
694cfde6 | 311 | $mut->assertSubjects(['Refund Notification - Annual CiviCRM meet - Mr. Anthony Anderson II']); |
d3b3ad06 | 312 | $mut->checkMailLog([ |
1e477c5b | 313 | 'Dear Anthony,', |
00ef9b01 | 314 | 'A refund has been issued based on changes in your registration selections.', |
1f6479af | 315 | 'Total Fee: $ 300' . $decimalSeparator . '00', |
a7b9128b | 316 | 'Refund Amount: $ -30' . $decimalSeparator . '00', |
b5a442ed | 317 | 'Event Information and Location', |
318 | 'Paid By: Check', | |
319 | 'Transaction Date: November 13th, 2018 12:01 PM', | |
1f6479af | 320 | 'Total Paid: $ 170' . $decimalSeparator . '00', |
d3b3ad06 | 321 | ]); |
b5a442ed | 322 | $mut->stop(); |
a7b9128b | 323 | $mut->clearMessages(); |
3d4f6f65 | 324 | $this->validateAllPayments(); |
b5a442ed | 325 | } |
326 | ||
5266bd48 | 327 | /** |
328 | * Test adding a payment to a pending multi-line order. | |
329 | * | |
330 | * @throws \CRM_Core_Exception | |
331 | */ | |
332 | public function testCreatePaymentPendingOrderNoLineItems() { | |
333 | $order = $this->createPendingParticipantOrder(); | |
334 | $this->callAPISuccess('Payment', 'create', [ | |
335 | 'order_id' => $order['id'], | |
336 | 'total_amount' => 50, | |
337 | ]); | |
3d4f6f65 | 338 | $this->validateAllPayments(); |
5266bd48 | 339 | } |
340 | ||
cc9f2882 | 341 | /** |
342 | * Test that Payment.create does not fail if the line items are missing. | |
343 | * | |
344 | * In the original spec it was anticipated that financial items would not be created | |
345 | * for pending contributions in some circumstances. We've backed away from this and | |
346 | * I mostly could not find a way to do it through the UI. But I did seem to once & | |
347 | * I want to be sure that if they ARE missing no fatal occurs so this tests | |
348 | * that in an artificial way. | |
349 | * | |
350 | * @throws \CRM_Core_Exception | |
351 | */ | |
352 | public function testAddPaymentMissingFinancialItems() { | |
353 | $contribution = $this->callAPISuccess('Contribution', 'create', [ | |
354 | 'total_amount' => 50, | |
355 | 'financial_type_id' => 'Donation', | |
356 | 'contact_id' => $this->individualCreate(), | |
357 | 'contribution_status_id' => 'Pending', | |
358 | ]); | |
359 | CRM_Core_DAO::executeQuery('DELETE FROM civicrm_financial_item'); | |
360 | $this->callAPISuccess('Payment', 'create', ['contribution_id' => $contribution['id'], 'payment_instrument_id' => 'Check', 'total_amount' => 5]); | |
361 | $this->validateAllPayments(); | |
362 | } | |
363 | ||
5266bd48 | 364 | /** |
365 | * Add participant with contribution | |
366 | * | |
367 | * @return array | |
368 | * | |
369 | * @throws \CRM_Core_Exception | |
370 | */ | |
371 | protected function createPendingParticipantOrder() { | |
372 | return $this->callAPISuccess('Order', 'create', $this->getParticipantOrderParams()); | |
373 | } | |
374 | ||
52873538 PN |
375 | /** |
376 | * Test create payment api with no line item in params | |
f3e6da5e | 377 | * |
378 | * @throws \CRM_Core_Exception | |
52873538 | 379 | */ |
b7f554fe | 380 | public function testCreatePaymentNoLineItems() { |
5266bd48 | 381 | $contribution = $this->createPartiallyPaidParticipantOrder(); |
f5ec2569 | 382 | |
b7f554fe | 383 | //Create partial payment |
d3b3ad06 | 384 | $params = [ |
b7f554fe | 385 | 'contribution_id' => $contribution['id'], |
52e3bed0 | 386 | 'total_amount' => 50, |
d3b3ad06 | 387 | ]; |
8ed3f575 | 388 | $payment = $this->callAPIAndDocument('payment', 'create', $params, __FUNCTION__, __FILE__); |
5049eefc | 389 | $this->checkPaymentIsValid($payment['id'], $contribution['id']); |
b7f554fe | 390 | |
d3b3ad06 | 391 | $params = [ |
577daeaa PN |
392 | 'entity_table' => 'civicrm_financial_item', |
393 | 'financial_trxn_id' => $payment['id'], | |
d3b3ad06 | 394 | ]; |
577daeaa | 395 | $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params); |
d3b3ad06 | 396 | $amounts = [33.33, 16.67]; |
577daeaa PN |
397 | foreach ($eft['values'] as $value) { |
398 | $this->assertEquals($value['amount'], array_pop($amounts)); | |
399 | } | |
400 | ||
b7f554fe | 401 | // Now create payment to complete total amount of contribution |
d3b3ad06 | 402 | $params = [ |
b7f554fe | 403 | 'contribution_id' => $contribution['id'], |
52e3bed0 | 404 | 'total_amount' => 100, |
d3b3ad06 | 405 | ]; |
c60d3584 | 406 | $payment = $this->callAPISuccess('payment', 'create', $params); |
d3b3ad06 | 407 | $expectedResult = [ |
408 | $payment['id'] => [ | |
c60d3584 PN |
409 | 'from_financial_account_id' => 7, |
410 | 'to_financial_account_id' => 6, | |
411 | 'total_amount' => 100, | |
412 | 'status_id' => 1, | |
413 | 'is_payment' => 1, | |
d3b3ad06 | 414 | ], |
415 | ]; | |
52e3bed0 | 416 | $this->checkPaymentResult($payment, $expectedResult); |
d3b3ad06 | 417 | $params = [ |
577daeaa PN |
418 | 'entity_table' => 'civicrm_financial_item', |
419 | 'financial_trxn_id' => $payment['id'], | |
d3b3ad06 | 420 | ]; |
577daeaa | 421 | $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params); |
d3b3ad06 | 422 | $amounts = [66.67, 33.33]; |
577daeaa PN |
423 | foreach ($eft['values'] as $value) { |
424 | $this->assertEquals($value['amount'], array_pop($amounts)); | |
425 | } | |
b7f554fe | 426 | // Check contribution for completed status |
d3b3ad06 | 427 | $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id']]); |
b7f554fe E |
428 | |
429 | $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Completed'); | |
52e3bed0 | 430 | $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 300.00); |
d3b3ad06 | 431 | $paymentParticipant = [ |
577daeaa | 432 | 'contribution_id' => $contribution['id'], |
d3b3ad06 | 433 | ]; |
577daeaa | 434 | $participantPayment = $this->callAPISuccess('ParticipantPayment', 'getsingle', $paymentParticipant); |
d3b3ad06 | 435 | $participant = $this->callAPISuccess('participant', 'get', ['id' => $participantPayment['participant_id']]); |
577daeaa | 436 | $this->assertEquals($participant['values'][$participant['id']]['participant_status'], 'Registered'); |
d3b3ad06 | 437 | $this->callAPISuccess('Contribution', 'Delete', [ |
b7f554fe | 438 | 'id' => $contribution['id'], |
d3b3ad06 | 439 | ]); |
3d4f6f65 | 440 | $this->validateAllPayments(); |
b7f554fe | 441 | } |
f5ec2569 | 442 | |
52e3bed0 PN |
443 | /** |
444 | * Function to assert db values | |
a494d7a3 | 445 | * |
446 | * @throws \CRM_Core_Exception | |
52e3bed0 PN |
447 | */ |
448 | public function checkPaymentResult($payment, $expectedResult) { | |
a494d7a3 | 449 | $refreshedPayment = $this->callAPISuccessGetSingle('Payment', ['financial_trxn_id' => $payment['id']]); |
c60d3584 | 450 | foreach ($expectedResult[$payment['id']] as $key => $value) { |
a494d7a3 | 451 | $this->assertEquals($refreshedPayment[$key], $value, 'mismatch on ' . $key); $this->assertEquals($refreshedPayment[$key], $value, 'mismatch on ' . $key); |
52e3bed0 | 452 | } |
52e3bed0 PN |
453 | } |
454 | ||
52873538 PN |
455 | /** |
456 | * Test create payment api with line item in params | |
5049eefc | 457 | * |
458 | * @throws \CRM_Core_Exception | |
52873538 | 459 | */ |
b7f554fe | 460 | public function testCreatePaymentLineItems() { |
5266bd48 | 461 | $contribution = $this->createPartiallyPaidParticipantOrder(); |
5049eefc | 462 | $lineItems = $this->callAPISuccess('LineItem', 'get', ['contribution_id' => $contribution['id']])['values']; |
b7f554fe | 463 | |
5049eefc | 464 | // Create partial payment by passing line item array is params. |
d3b3ad06 | 465 | $params = [ |
b7f554fe | 466 | 'contribution_id' => $contribution['id'], |
d1f27fcf | 467 | 'total_amount' => 50, |
d3b3ad06 | 468 | ]; |
469 | $amounts = [40, 10]; | |
5049eefc | 470 | foreach ($lineItems as $id => $ignore) { |
d3b3ad06 | 471 | $params['line_item'][] = [$id => array_pop($amounts)]; |
d1f27fcf | 472 | } |
5049eefc | 473 | $payment = $this->callAPIAndDocument('Payment', 'create', $params, __FUNCTION__, __FILE__, 'Payment with line item', 'CreatePaymentWithLineItems'); |
474 | $this->checkPaymentIsValid($payment['id'], $contribution['id']); | |
d1f27fcf | 475 | |
d3b3ad06 | 476 | $params = [ |
d1f27fcf PN |
477 | 'entity_table' => 'civicrm_financial_item', |
478 | 'financial_trxn_id' => $payment['id'], | |
5049eefc | 479 | 'return' => ['entity_id.entity_id', 'amount'], |
d3b3ad06 | 480 | ]; |
5049eefc | 481 | $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params)['values']; |
482 | $this->assertCount(2, $eft); | |
d3b3ad06 | 483 | $amounts = [40, 10]; |
5049eefc | 484 | foreach ($eft as $value) { |
d1f27fcf PN |
485 | $this->assertEquals($value['amount'], array_pop($amounts)); |
486 | } | |
b7f554fe E |
487 | |
488 | // Now create payment to complete total amount of contribution | |
d3b3ad06 | 489 | $params = [ |
b7f554fe | 490 | 'contribution_id' => $contribution['id'], |
d1f27fcf | 491 | 'total_amount' => 100, |
d3b3ad06 | 492 | ]; |
493 | $amounts = [80, 20]; | |
5049eefc | 494 | foreach ($lineItems as $id => $ignore) { |
d3b3ad06 | 495 | $params['line_item'][] = [$id => array_pop($amounts)]; |
d1f27fcf | 496 | } |
5049eefc | 497 | $payment = $this->callAPISuccess('Payment', 'create', $params); |
d3b3ad06 | 498 | $expectedResult = [ |
499 | $payment['id'] => [ | |
c60d3584 PN |
500 | 'from_financial_account_id' => 7, |
501 | 'to_financial_account_id' => 6, | |
502 | 'total_amount' => 100, | |
503 | 'status_id' => 1, | |
504 | 'is_payment' => 1, | |
d3b3ad06 | 505 | ], |
506 | ]; | |
d1f27fcf | 507 | $this->checkPaymentResult($payment, $expectedResult); |
d3b3ad06 | 508 | $params = [ |
d1f27fcf PN |
509 | 'entity_table' => 'civicrm_financial_item', |
510 | 'financial_trxn_id' => $payment['id'], | |
d3b3ad06 | 511 | ]; |
5049eefc | 512 | $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params)['values']; |
513 | $this->assertCount(2, $eft); | |
d3b3ad06 | 514 | $amounts = [80, 20]; |
5049eefc | 515 | foreach ($eft as $value) { |
d1f27fcf PN |
516 | $this->assertEquals($value['amount'], array_pop($amounts)); |
517 | } | |
b7f554fe | 518 | // Check contribution for completed status |
5049eefc | 519 | $contribution = $this->callAPISuccess('Contribution', 'get', ['id' => $contribution['id']]); |
b7f554fe E |
520 | |
521 | $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Completed'); | |
d1f27fcf | 522 | $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 300.00); |
d3b3ad06 | 523 | $paymentParticipant = [ |
d1f27fcf | 524 | 'contribution_id' => $contribution['id'], |
d3b3ad06 | 525 | ]; |
d1f27fcf | 526 | $participantPayment = $this->callAPISuccess('ParticipantPayment', 'getsingle', $paymentParticipant); |
d3b3ad06 | 527 | $participant = $this->callAPISuccess('participant', 'get', ['id' => $participantPayment['participant_id']]); |
d1f27fcf | 528 | $this->assertEquals($participant['values'][$participant['id']]['participant_status'], 'Registered'); |
3d4f6f65 | 529 | $this->validateAllPayments(); |
b7f554fe E |
530 | } |
531 | ||
b87ee4c1 JP |
532 | /** |
533 | * Test negative payment using create API. | |
bb5eaaf0 TO |
534 | * |
535 | * @throws \CRM_Core_Exception | |
b87ee4c1 JP |
536 | */ |
537 | public function testRefundPayment() { | |
538 | $result = $this->callAPISuccess('Contribution', 'create', [ | |
539 | 'financial_type_id' => "Donation", | |
540 | 'total_amount' => 100, | |
541 | 'contact_id' => $this->_individualId, | |
542 | ]); | |
543 | $contributionID = $result['id']; | |
544 | ||
545 | //Refund a part of the main amount. | |
546 | $this->callAPISuccess('Payment', 'create', [ | |
547 | 'contribution_id' => $contributionID, | |
548 | 'total_amount' => -10, | |
549 | ]); | |
550 | ||
551 | $contribution = $this->callAPISuccessGetSingle('Contribution', [ | |
552 | 'return' => ["contribution_status_id"], | |
553 | 'id' => $contributionID, | |
554 | ]); | |
555 | //Still we've a status of Completed after refunding a partial amount. | |
556 | $this->assertEquals($contribution['contribution_status'], 'Completed'); | |
557 | ||
558 | //Refund the complete amount. | |
559 | $this->callAPISuccess('Payment', 'create', [ | |
560 | 'contribution_id' => $contributionID, | |
561 | 'total_amount' => -90, | |
562 | ]); | |
563 | $contribution = $this->callAPISuccessGetSingle('Contribution', [ | |
d2aeabca | 564 | 'return' => ['contribution_status_id'], |
b87ee4c1 JP |
565 | 'id' => $contributionID, |
566 | ]); | |
567 | //Assert if main contribution status is updated to "Refunded". | |
568 | $this->assertEquals($contribution['contribution_status'], 'Refunded Label**'); | |
569 | } | |
570 | ||
db62fd2b PN |
571 | /** |
572 | * Test cancel payment api | |
5049eefc | 573 | * |
574 | * @throws \CRM_Core_Exception | |
2fabb298 | 575 | */ |
db62fd2b | 576 | public function testCancelPayment() { |
d3b3ad06 | 577 | CRM_Core_Config::singleton()->userPermissionClass->permissions = ['administer CiviCRM', 'access CiviContribute']; |
5266bd48 | 578 | $contribution = $this->createPartiallyPaidParticipantOrder(); |
db62fd2b | 579 | |
d3b3ad06 | 580 | $params = [ |
db62fd2b | 581 | 'contribution_id' => $contribution['id'], |
d3b3ad06 | 582 | ]; |
db62fd2b | 583 | |
979748a2 | 584 | $payment = $this->callAPISuccess('payment', 'get', $params); |
db62fd2b PN |
585 | $this->assertEquals(1, $payment['count']); |
586 | ||
d3b3ad06 | 587 | $cancelParams = [ |
db62fd2b | 588 | 'id' => $payment['id'], |
979748a2 | 589 | 'check_permissions' => TRUE, |
d3b3ad06 | 590 | ]; |
d2aeabca | 591 | $this->callAPIFailure('payment', 'cancel', $cancelParams, 'API permission check failed for Payment/cancel call; insufficient permission: require access CiviCRM and access CiviContribute and edit contributions'); |
979748a2 | 592 | |
eba13f6d | 593 | array_push(CRM_Core_Config::singleton()->userPermissionClass->permissions, 'access CiviCRM', 'edit contributions'); |
979748a2 | 594 | |
8ed3f575 | 595 | $this->callAPIAndDocument('payment', 'cancel', $cancelParams, __FUNCTION__, __FILE__); |
db62fd2b | 596 | |
c60d3584 | 597 | $payment = $this->callAPISuccess('payment', 'get', $params); |
db62fd2b | 598 | $this->assertEquals(2, $payment['count']); |
d3b3ad06 | 599 | $amounts = [-150.00, 150.00]; |
2fabb298 | 600 | foreach ($payment['values'] as $value) { |
db62fd2b PN |
601 | $this->assertEquals($value['total_amount'], array_pop($amounts), 'Mismatch total amount'); |
602 | } | |
603 | ||
d3b3ad06 | 604 | $this->callAPISuccess('Contribution', 'Delete', [ |
db62fd2b | 605 | 'id' => $contribution['id'], |
d3b3ad06 | 606 | ]); |
3d4f6f65 | 607 | $this->validateAllPayments(); |
db62fd2b PN |
608 | } |
609 | ||
ee1f482b PN |
610 | /** |
611 | * Test delete payment api | |
3d4f6f65 | 612 | * |
613 | * @throws \CRM_Core_Exception | |
ee1f482b PN |
614 | */ |
615 | public function testDeletePayment() { | |
d3b3ad06 | 616 | CRM_Core_Config::singleton()->userPermissionClass->permissions = ['administer CiviCRM', 'access CiviContribute']; |
5266bd48 | 617 | $contribution = $this->createPartiallyPaidParticipantOrder(); |
ee1f482b | 618 | |
d3b3ad06 | 619 | $params = [ |
ee1f482b | 620 | 'contribution_id' => $contribution['id'], |
d3b3ad06 | 621 | ]; |
ee1f482b | 622 | |
d2aeabca | 623 | $payment = $this->callAPISuccessGetSingle('payment', $params); |
ee1f482b | 624 | |
d3b3ad06 | 625 | $deleteParams = [ |
ee1f482b | 626 | 'id' => $payment['id'], |
979748a2 | 627 | 'check_permissions' => TRUE, |
d3b3ad06 | 628 | ]; |
d2aeabca | 629 | $this->callAPIFailure('payment', 'delete', $deleteParams, 'API permission check failed for Payment/delete call; insufficient permission: require access CiviCRM and access CiviContribute and delete in CiviContribute'); |
979748a2 | 630 | |
eba13f6d | 631 | array_push(CRM_Core_Config::singleton()->userPermissionClass->permissions, 'access CiviCRM', 'delete in CiviContribute'); |
8ed3f575 | 632 | $this->callAPIAndDocument('payment', 'delete', $deleteParams, __FUNCTION__, __FILE__); |
d2aeabca | 633 | $this->callAPISuccessGetCount('payment', $params, 0); |
ee1f482b | 634 | |
d2aeabca | 635 | $this->callAPISuccess('Contribution', 'Delete', ['id' => $contribution['id']]); |
ee1f482b PN |
636 | } |
637 | ||
4cdb5e2f | 638 | /** |
36057c8d | 639 | * Test update payment api. |
640 | * | |
641 | * 1) create a contribution for $300 with a partial payment of $150 | |
642 | * - this results in 2 financial transactions. The accounts receivable transaction is linked | |
643 | * via entity_financial_trxns to the 2 line items. The $150 payment is not linked to the line items | |
644 | * so the line items are fully allocated even though they are only half paid. | |
645 | * | |
646 | * 2) add a payment of $50 - | |
647 | * This payment transaction IS linked to the line items so $350 of the $300 in line items is allocated | |
648 | * but $200 is paid | |
649 | * | |
650 | * 3) update that payment to be $100 | |
651 | * This results in a negative and a positive payment ($50 & $100) - the negative payment results in | |
652 | * financial_items but the positive payment does not. | |
653 | * | |
654 | * The final result is we have | |
655 | * - 1 partly paid contribution of $300 | |
656 | * - payment financial_trxns totalling $250 | |
657 | * - 1 Accounts receivable financial_trxn totalling $300 | |
658 | * - 2 financial items totalling $300 linked to the Accounts receivable financial_trxn | |
659 | * - 6 entries in the civicrm_entity_financial_trxn linked to line items - totalling $450. | |
660 | * - 5 entries in the civicrm_entity_financial_trxn linked to contributions - totalling $550. | |
6aa56ee2 | 661 | * |
662 | * @throws \CRM_Core_Exception | |
4cdb5e2f PN |
663 | */ |
664 | public function testUpdatePayment() { | |
d3b3ad06 | 665 | CRM_Core_Config::singleton()->userPermissionClass->permissions = ['administer CiviCRM', 'access CiviContribute', 'edit contributions']; |
5266bd48 | 666 | $contribution = $this->createPartiallyPaidParticipantOrder(); |
4cdb5e2f PN |
667 | |
668 | //Create partial payment by passing line item array is params | |
d3b3ad06 | 669 | $params = [ |
4cdb5e2f PN |
670 | 'contribution_id' => $contribution['id'], |
671 | 'total_amount' => 50, | |
d3b3ad06 | 672 | ]; |
4cdb5e2f | 673 | |
c60d3584 | 674 | $payment = $this->callAPISuccess('payment', 'create', $params); |
d3b3ad06 | 675 | $expectedResult = [ |
676 | $payment['id'] => [ | |
c60d3584 PN |
677 | 'from_financial_account_id' => 7, |
678 | 'to_financial_account_id' => 6, | |
679 | 'total_amount' => 50, | |
680 | 'status_id' => 1, | |
681 | 'is_payment' => 1, | |
d3b3ad06 | 682 | ], |
683 | ]; | |
4cdb5e2f PN |
684 | $this->checkPaymentResult($payment, $expectedResult); |
685 | ||
d3b3ad06 | 686 | $params = [ |
4cdb5e2f PN |
687 | 'entity_table' => 'civicrm_financial_item', |
688 | 'financial_trxn_id' => $payment['id'], | |
d3b3ad06 | 689 | ]; |
4cdb5e2f | 690 | $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params); |
d3b3ad06 | 691 | $amounts = [33.33, 16.67]; |
4cdb5e2f PN |
692 | foreach ($eft['values'] as $value) { |
693 | $this->assertEquals($value['amount'], array_pop($amounts)); | |
694 | } | |
695 | ||
696 | // update the amount for payment | |
d3b3ad06 | 697 | $params = [ |
4cdb5e2f PN |
698 | 'contribution_id' => $contribution['id'], |
699 | 'total_amount' => 100, | |
700 | 'id' => $payment['id'], | |
979748a2 | 701 | 'check_permissions' => TRUE, |
d3b3ad06 | 702 | ]; |
36057c8d | 703 | // @todo - move this permissions test to it's own test - it just confuses here. |
704 | CRM_Core_Config::singleton()->userPermissionClass->permissions = ['administer CiviCRM', 'access CiviContribute']; | |
705 | $this->callAPIFailure('payment', 'create', $params, 'API permission check failed for Payment/create call; insufficient permission: require access CiviCRM and access CiviContribute and edit contributions'); | |
979748a2 | 706 | |
36057c8d | 707 | CRM_Core_Config::singleton()->userPermissionClass->permissions = ['administer CiviCRM', 'access CiviContribute', 'access CiviCRM', 'edit contributions']; |
8ed3f575 | 708 | $payment = $this->callAPIAndDocument('payment', 'create', $params, __FUNCTION__, __FILE__, 'Update Payment', 'UpdatePayment'); |
4cdb5e2f | 709 | |
6ac768e7 | 710 | $this->validateAllPayments(); |
2a84219e | 711 | // Check for proportional cancelled payment against lineitems. |
d3b3ad06 | 712 | $minParams = [ |
2a84219e E |
713 | 'entity_table' => 'civicrm_financial_item', |
714 | 'financial_trxn_id' => $payment['id'] - 1, | |
d3b3ad06 | 715 | ]; |
2a84219e | 716 | |
df29ccff | 717 | $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $minParams)['values']; |
718 | $this->assertCount(2, $eft); | |
d3b3ad06 | 719 | $amounts = [-33.33, -16.67]; |
2a84219e | 720 | |
df29ccff | 721 | foreach ($eft as $value) { |
2a84219e E |
722 | $this->assertEquals($value['amount'], array_pop($amounts)); |
723 | } | |
724 | ||
725 | // Check for proportional updated payment against lineitems. | |
d3b3ad06 | 726 | $params = [ |
4cdb5e2f PN |
727 | 'entity_table' => 'civicrm_financial_item', |
728 | 'financial_trxn_id' => $payment['id'], | |
d3b3ad06 | 729 | ]; |
df29ccff | 730 | $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params)['values']; |
d3b3ad06 | 731 | $amounts = [66.67, 33.33]; |
df29ccff | 732 | foreach ($eft as $value) { |
4cdb5e2f PN |
733 | $this->assertEquals($value['amount'], array_pop($amounts)); |
734 | } | |
36057c8d | 735 | $items = $this->callAPISuccess('FinancialItem', 'get', [])['values']; |
736 | $this->assertCount(2, $items); | |
737 | $itemSum = 0; | |
738 | foreach ($items as $item) { | |
739 | $this->assertEquals('civicrm_line_item', $item['entity_table']); | |
740 | $itemSum += $item['amount']; | |
741 | } | |
742 | $this->assertEquals(300, $itemSum); | |
4cdb5e2f | 743 | |
d3b3ad06 | 744 | $params = [ |
4cdb5e2f | 745 | 'contribution_id' => $contribution['id'], |
d3b3ad06 | 746 | ]; |
c60d3584 | 747 | $payment = $this->callAPISuccess('payment', 'get', $params); |
d3b3ad06 | 748 | $amounts = [100.00, -50.00, 50.00, 150.00]; |
4cdb5e2f PN |
749 | foreach ($payment['values'] as $value) { |
750 | $amount = array_pop($amounts); | |
751 | $this->assertEquals($value['total_amount'], $amount, 'Mismatch total amount'); | |
752 | ||
753 | // Check entity financial trxn created properly | |
d3b3ad06 | 754 | $params = [ |
4cdb5e2f PN |
755 | 'entity_id' => $contribution['id'], |
756 | 'entity_table' => 'civicrm_contribution', | |
757 | 'financial_trxn_id' => $value['id'], | |
d3b3ad06 | 758 | ]; |
4cdb5e2f PN |
759 | $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params); |
760 | $this->assertEquals($eft['values'][$eft['id']]['amount'], $amount); | |
761 | } | |
762 | ||
d3b3ad06 | 763 | $this->callAPISuccess('Contribution', 'Delete', [ |
4cdb5e2f | 764 | 'id' => $contribution['id'], |
d3b3ad06 | 765 | ]); |
3d4f6f65 | 766 | $this->validateAllPayments(); |
4cdb5e2f PN |
767 | } |
768 | ||
4804f442 | 769 | /** |
770 | * Test that a contribution can be overpaid with the payment api. | |
771 | * | |
772 | * @throws \CRM_Core_Exception | |
773 | */ | |
774 | public function testCreatePaymentOverPay() { | |
775 | $contributionID = $this->contributionCreate(['contact_id' => $this->individualCreate()]); | |
776 | $payment = $this->callAPISuccess('Payment', 'create', ['total_amount' => 5, 'order_id' => $contributionID]); | |
777 | $contribution = $this->callAPISuccessGetSingle('Contribution', ['id' => $contributionID]); | |
778 | $this->assertEquals('Completed', $contribution['contribution_status']); | |
779 | $this->callAPISuccessGetCount('EntityFinancialTrxn', ['financial_trxn_id' => $payment['id'], 'entity_table' => 'civicrm_financial_item'], 0); | |
780 | $this->validateAllPayments(); | |
781 | $this->validateAllContributions(); | |
782 | } | |
783 | ||
c60d3584 PN |
784 | /** |
785 | * Test create payment api for paylater contribution | |
3d4f6f65 | 786 | * |
787 | * @throws \CRM_Core_Exception | |
c60d3584 PN |
788 | */ |
789 | public function testCreatePaymentPayLater() { | |
790 | $this->createLoggedInUser(); | |
a494d7a3 | 791 | $processorID = $this->paymentProcessorCreate(); |
d3b3ad06 | 792 | $contributionParams = [ |
c60d3584 PN |
793 | 'total_amount' => 100, |
794 | 'currency' => 'USD', | |
795 | 'contact_id' => $this->_individualId, | |
796 | 'financial_type_id' => 1, | |
797 | 'contribution_status_id' => 2, | |
798 | 'is_pay_later' => 1, | |
d3b3ad06 | 799 | ]; |
c60d3584 | 800 | $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams); |
8ed3f575 | 801 | //add payment for pay later transaction |
d3b3ad06 | 802 | $params = [ |
c60d3584 PN |
803 | 'contribution_id' => $contribution['id'], |
804 | 'total_amount' => 100, | |
a494d7a3 | 805 | 'card_type_id' => 'Visa', |
806 | 'pan_truncation' => '1234', | |
807 | 'trxn_result_code' => 'Startling success', | |
808 | 'payment_instrument_id' => $processorID, | |
809 | 'trxn_id' => 1234, | |
d3b3ad06 | 810 | ]; |
c60d3584 | 811 | $payment = $this->callAPISuccess('Payment', 'create', $params); |
d3b3ad06 | 812 | $expectedResult = [ |
813 | $payment['id'] => [ | |
c60d3584 PN |
814 | 'from_financial_account_id' => 7, |
815 | 'to_financial_account_id' => 6, | |
816 | 'total_amount' => 100, | |
817 | 'status_id' => 1, | |
818 | 'is_payment' => 1, | |
a494d7a3 | 819 | 'card_type_id' => 1, |
820 | 'pan_truncation' => '1234', | |
821 | 'trxn_result_code' => 'Startling success', | |
822 | 'trxn_id' => 1234, | |
823 | 'payment_instrument_id' => 1, | |
d3b3ad06 | 824 | ], |
825 | ]; | |
c60d3584 PN |
826 | $this->checkPaymentResult($payment, $expectedResult); |
827 | // Check entity financial trxn created properly | |
d3b3ad06 | 828 | $params = [ |
c60d3584 PN |
829 | 'entity_id' => $contribution['id'], |
830 | 'entity_table' => 'civicrm_contribution', | |
831 | 'financial_trxn_id' => $payment['id'], | |
d3b3ad06 | 832 | ]; |
c60d3584 PN |
833 | $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params); |
834 | $this->assertEquals($eft['values'][$eft['id']]['amount'], 100); | |
d3b3ad06 | 835 | $params = [ |
c60d3584 PN |
836 | 'entity_table' => 'civicrm_financial_item', |
837 | 'financial_trxn_id' => $payment['id'], | |
d3b3ad06 | 838 | ]; |
c60d3584 PN |
839 | $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params); |
840 | $this->assertEquals($eft['values'][$eft['id']]['amount'], 100); | |
841 | // Check contribution for completed status | |
d3b3ad06 | 842 | $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id']]); |
c60d3584 PN |
843 | $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Completed'); |
844 | $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00); | |
d3b3ad06 | 845 | $this->callAPISuccess('Contribution', 'Delete', [ |
c60d3584 | 846 | 'id' => $contribution['id'], |
d3b3ad06 | 847 | ]); |
3d4f6f65 | 848 | $this->validateAllPayments(); |
c60d3584 PN |
849 | } |
850 | ||
f5269434 | 851 | /** |
852 | * Test net amount is set when fee amount is passed in. | |
853 | * | |
854 | * @throws \CRM_Core_Exception | |
855 | */ | |
856 | public function testNetAmount() { | |
857 | $order = $this->createPendingParticipantOrder(); | |
858 | $payment = $this->callAPISuccess('Payment', 'create', ['order_id' => $order['id'], 'total_amount' => 10, 'fee_amount' => .25]); | |
859 | $this->assertEquals('9.75', $this->callAPISuccessGetValue('Payment', ['id' => $payment['id'], 'return' => 'net_amount'])); | |
860 | } | |
861 | ||
d5b39a17 | 862 | /** |
8d54448e | 863 | * Test create payment api for pay later contribution with partial payment. |
864 | * | |
16b0233c | 865 | * https://lab.civicrm.org/dev/financial/issues/69 |
3d4f6f65 | 866 | * @throws \CRM_Core_Exception |
16b0233c | 867 | */ |
868 | public function testCreatePaymentIncompletePaymentPartialPayment() { | |
869 | $contributionParams = [ | |
870 | 'total_amount' => 100, | |
871 | 'currency' => 'USD', | |
872 | 'contact_id' => $this->_individualId, | |
873 | 'financial_type_id' => 1, | |
874 | 'contribution_status_id' => 2, | |
875 | ]; | |
876 | $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams); | |
877 | $this->callAPISuccess('Payment', 'create', [ | |
878 | 'contribution_id' => $contribution['id'], | |
879 | 'total_amount' => 50, | |
880 | 'payment_instrument_id' => 'Cash', | |
881 | ]); | |
882 | $payments = $this->callAPISuccess('Payment', 'get', ['contribution_id' => $contribution['id']])['values']; | |
883 | $this->assertCount(1, $payments); | |
3d4f6f65 | 884 | $this->validateAllPayments(); |
16b0233c | 885 | } |
886 | ||
887 | /** | |
888 | * Test create payment api for pay later contribution with partial payment. | |
6cc6cb8c | 889 | * |
890 | * @throws \CRM_Core_Exception | |
d5b39a17 PN |
891 | */ |
892 | public function testCreatePaymentPayLaterPartialPayment() { | |
893 | $this->createLoggedInUser(); | |
d3b3ad06 | 894 | $contributionParams = [ |
d5b39a17 PN |
895 | 'total_amount' => 100, |
896 | 'currency' => 'USD', | |
897 | 'contact_id' => $this->_individualId, | |
898 | 'financial_type_id' => 1, | |
899 | 'contribution_status_id' => 2, | |
900 | 'is_pay_later' => 1, | |
d3b3ad06 | 901 | ]; |
6cc6cb8c | 902 | $contribution = $this->callAPISuccess('Order', 'create', $contributionParams); |
d5b39a17 | 903 | //Create partial payment |
d3b3ad06 | 904 | $params = [ |
d5b39a17 PN |
905 | 'contribution_id' => $contribution['id'], |
906 | 'total_amount' => 60, | |
d3b3ad06 | 907 | ]; |
d5b39a17 | 908 | $payment = $this->callAPISuccess('Payment', 'create', $params); |
d3b3ad06 | 909 | $expectedResult = [ |
910 | $payment['id'] => [ | |
d5b39a17 PN |
911 | 'total_amount' => 60, |
912 | 'status_id' => 1, | |
913 | 'is_payment' => 1, | |
d3b3ad06 | 914 | ], |
915 | ]; | |
d5b39a17 PN |
916 | $this->checkPaymentResult($payment, $expectedResult); |
917 | // Check entity financial trxn created properly | |
d3b3ad06 | 918 | $params = [ |
d5b39a17 PN |
919 | 'entity_id' => $contribution['id'], |
920 | 'entity_table' => 'civicrm_contribution', | |
921 | 'financial_trxn_id' => $payment['id'], | |
d3b3ad06 | 922 | ]; |
d5b39a17 PN |
923 | $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params); |
924 | $this->assertEquals($eft['values'][$eft['id']]['amount'], 60); | |
d3b3ad06 | 925 | $params = [ |
d5b39a17 PN |
926 | 'entity_table' => 'civicrm_financial_item', |
927 | 'financial_trxn_id' => $payment['id'], | |
d3b3ad06 | 928 | ]; |
d5b39a17 PN |
929 | $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params); |
930 | $this->assertEquals($eft['values'][$eft['id']]['amount'], 60); | |
d3b3ad06 | 931 | $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id']]); |
d5b39a17 PN |
932 | $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Partially paid'); |
933 | $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00); | |
934 | //Create full payment | |
d3b3ad06 | 935 | $params = [ |
d5b39a17 PN |
936 | 'contribution_id' => $contribution['id'], |
937 | 'total_amount' => 40, | |
d3b3ad06 | 938 | ]; |
0a201857 | 939 | // Rename the 'completed' status label first to check that we are not using the labels! |
940 | $this->callAPISuccess('OptionValue', 'get', ['name' => 'Completed', 'option_group_id' => 'contribution_status', 'api.OptionValue.create' => ['label' => 'Unicorn']]); | |
d5b39a17 | 941 | $payment = $this->callAPISuccess('Payment', 'create', $params); |
d3b3ad06 | 942 | $expectedResult = [ |
943 | $payment['id'] => [ | |
d5b39a17 PN |
944 | 'from_financial_account_id' => 7, |
945 | 'to_financial_account_id' => 6, | |
946 | 'total_amount' => 40, | |
947 | 'status_id' => 1, | |
948 | 'is_payment' => 1, | |
d3b3ad06 | 949 | ], |
950 | ]; | |
d5b39a17 PN |
951 | $this->checkPaymentResult($payment, $expectedResult); |
952 | // Check entity financial trxn created properly | |
d3b3ad06 | 953 | $params = [ |
d5b39a17 PN |
954 | 'entity_id' => $contribution['id'], |
955 | 'entity_table' => 'civicrm_contribution', | |
956 | 'financial_trxn_id' => $payment['id'], | |
d3b3ad06 | 957 | ]; |
d5b39a17 PN |
958 | $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params); |
959 | $this->assertEquals($eft['values'][$eft['id']]['amount'], 40); | |
d3b3ad06 | 960 | $params = [ |
d5b39a17 PN |
961 | 'entity_table' => 'civicrm_financial_item', |
962 | 'financial_trxn_id' => $payment['id'], | |
d3b3ad06 | 963 | ]; |
d5b39a17 PN |
964 | $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params); |
965 | $this->assertEquals($eft['values'][$eft['id']]['amount'], 40); | |
966 | // Check contribution for completed status | |
d3b3ad06 | 967 | $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id']]); |
0a201857 | 968 | $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Unicorn'); |
d5b39a17 | 969 | $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00); |
d3b3ad06 | 970 | $this->callAPISuccess('Contribution', 'Delete', [ |
d5b39a17 | 971 | 'id' => $contribution['id'], |
d3b3ad06 | 972 | ]); |
0a201857 | 973 | $this->callAPISuccess('OptionValue', 'get', ['name' => 'Completed', 'option_group_id' => 'contribution_status', 'api.OptionValue.create' => ['label' => 'Completed']]); |
8d54448e | 974 | $this->callAPISuccessGetCount('Activity', ['target_contact_id' => $this->_individualId, 'activity_type_id' => 'Payment'], 2); |
3d4f6f65 | 975 | $this->validateAllPayments(); |
d5b39a17 PN |
976 | } |
977 | ||
6cc6cb8c | 978 | /** |
979 | * Test that Payment.create uses the to_account of the payment processor. | |
980 | * | |
981 | * @throws \CiviCRM_API3_Exception | |
982 | * @throws \CRM_Core_Exception | |
983 | */ | |
984 | public function testPaymentWithProcessorWithOddFinancialAccount() { | |
985 | $processor = $this->dummyProcessorCreate(['financial_account_id' => 'Deposit Bank Account', 'payment_instrument_id' => 'Cash']); | |
986 | $processor2 = $this->dummyProcessorCreate(['financial_account_id' => 'Payment Processor Account', 'name' => 'p2', 'payment_instrument_id' => 'EFT']); | |
987 | $contributionParams = [ | |
988 | 'total_amount' => 100, | |
989 | 'currency' => 'USD', | |
990 | 'contact_id' => $this->_individualId, | |
991 | 'financial_type_id' => 1, | |
992 | 'contribution_status_id' => 'Pending', | |
993 | ]; | |
994 | $order = $this->callAPISuccess('Order', 'create', $contributionParams); | |
995 | $this->callAPISuccess('Payment', 'create', ['payment_processor_id' => $processor->getID(), 'total_amount' => 6, 'contribution_id' => $order['id']]); | |
996 | $this->callAPISuccess('Payment', 'create', ['payment_processor_id' => $processor2->getID(), 'total_amount' => 15, 'contribution_id' => $order['id']]); | |
997 | $payments = $this->callAPISuccess('Payment', 'get', ['sequential' => 1, 'contribution_id' => $order['id']])['values']; | |
998 | $this->assertEquals('Deposit Bank Account', CRM_Core_PseudoConstant::getName('CRM_Core_BAO_FinancialTrxn', 'to_financial_account_id', $payments[0]['to_financial_account_id'])); | |
999 | $this->assertEquals('Payment Processor Account', CRM_Core_PseudoConstant::getName('CRM_Core_BAO_FinancialTrxn', 'to_financial_account_id', $payments[1]['to_financial_account_id'])); | |
1000 | $this->assertEquals('Accounts Receivable', CRM_Core_PseudoConstant::getName('CRM_Core_BAO_FinancialTrxn', 'from_financial_account_id', $payments[0]['from_financial_account_id'])); | |
1001 | $this->assertEquals('Accounts Receivable', CRM_Core_PseudoConstant::getName('CRM_Core_BAO_FinancialTrxn', 'from_financial_account_id', $payments[1]['from_financial_account_id'])); | |
1002 | $this->assertEquals('Cash', CRM_Core_PseudoConstant::getName('CRM_Core_BAO_FinancialTrxn', 'payment_instrument_id', $payments[0]['payment_instrument_id'])); | |
1003 | $this->assertEquals('EFT', CRM_Core_PseudoConstant::getName('CRM_Core_BAO_FinancialTrxn', 'payment_instrument_id', $payments[1]['payment_instrument_id'])); | |
1004 | // $order = $this->callAPISuccessGetSingle('Order', ['id' => $processor->getID()]); | |
1005 | // $this->assertEquals('Cash', CRM_Core_PseudoConstant::getName('CRM_Core_BAO_FinancialTrxn', 'payment_instrument_id', $order['payment_instrument_id'])); | |
1006 | } | |
1007 | ||
0fad34a0 | 1008 | /** |
1009 | * Add a location to our event. | |
1010 | * | |
1011 | * @param int $eventID | |
6cc6cb8c | 1012 | * |
1013 | * @throws \CRM_Core_Exception | |
0fad34a0 | 1014 | */ |
1015 | protected function addLocationToEvent($eventID) { | |
1016 | $addressParams = [ | |
1017 | 'name' => 'event place', | |
1018 | 'street_address' => 'streety street', | |
1019 | 'location_type_id' => 1, | |
1020 | 'is_primary' => 1, | |
1021 | ]; | |
1022 | // api requires contact_id - perhaps incorrectly but use add to get past that. | |
1023 | $address = CRM_Core_BAO_Address::add($addressParams); | |
1024 | ||
1025 | $location = $this->callAPISuccess('LocBlock', 'create', ['address_id' => $address->id]); | |
1026 | $this->callAPISuccess('Event', 'create', [ | |
1027 | 'id' => $eventID, | |
1028 | 'loc_block_id' => $location['id'], | |
1029 | 'is_show_location' => TRUE, | |
1030 | ]); | |
3d4f6f65 | 1031 | $this->validateAllPayments(); |
0fad34a0 | 1032 | } |
1033 | ||
5049eefc | 1034 | /** |
1035 | * Check the created payment is valid. | |
1036 | * | |
1037 | * This is probably over-testing really since we are repetitively checking a basic function... | |
1038 | * | |
1039 | * @param int $paymentID | |
1040 | * @param int $contributionID | |
1041 | * @param int $amount | |
1042 | * | |
1043 | * @throws \CRM_Core_Exception | |
1044 | */ | |
1045 | protected function checkPaymentIsValid($paymentID, $contributionID, $amount = 50) { | |
1046 | $payment = $this->callAPISuccess('Payment', 'getsingle', ['financial_trxn_id' => $paymentID]); | |
1047 | $this->assertEquals(7, $payment['from_financial_account_id']); | |
1048 | $this->assertEquals(6, $payment['to_financial_account_id']); | |
1049 | $this->assertEquals(1, $payment['status_id']); | |
1050 | $this->assertEquals(1, $payment['is_payment']); | |
1051 | $this->assertEquals($amount, $payment['total_amount']); | |
1052 | ||
1053 | $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', [ | |
1054 | 'entity_id' => $contributionID, | |
1055 | 'entity_table' => 'civicrm_contribution', | |
1056 | 'financial_trxn_id' => $payment['id'], | |
1057 | ]); | |
1058 | ||
1059 | $this->assertEquals($eft['values'][$eft['id']]['amount'], $amount); | |
3d4f6f65 | 1060 | $this->validateAllPayments(); |
5049eefc | 1061 | } |
1062 | ||
b7f554fe | 1063 | } |