Merge pull request #15412 from demeritcowboy/fly-backwards
[civicrm-core.git] / tests / phpunit / api / v3 / PaymentTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 * Test APIv3 civicrm_contribute_* functions
30 *
31 * @package CiviCRM_APIv3
32 * @subpackage API_Contribution
33 * @group headless
34 */
35 class api_v3_PaymentTest extends CiviUnitTestCase {
36
37 protected $_individualId;
38
39 protected $_financialTypeId = 1;
40
41 protected $_apiversion;
42
43 public $debug = 0;
44
45 /**
46 * Setup function.
47 */
48 public function setUp() {
49 parent::setUp();
50
51 $this->_apiversion = 3;
52 $this->_individualId = $this->individualCreate();
53 CRM_Core_Config::singleton()->userPermissionClass->permissions = [];
54 }
55
56 /**
57 * Clean up after each test.
58 *
59 * @throws \Exception
60 */
61 public function tearDown() {
62 $this->quickCleanUpFinancialEntities();
63 $this->quickCleanup(['civicrm_uf_match']);
64 unset(CRM_Core_Config::singleton()->userPermissionClass->permissions);
65 parent::tearDown();
66 }
67
68 /**
69 * Test Get Payment api.
70 */
71 public function testGetPayment() {
72 $p = [
73 'contact_id' => $this->_individualId,
74 'receive_date' => '2010-01-20',
75 'total_amount' => 100.00,
76 'financial_type_id' => $this->_financialTypeId,
77 'trxn_id' => 23456,
78 'contribution_status_id' => 1,
79 ];
80 $contribution = $this->callAPISuccess('contribution', 'create', $p);
81
82 $params = [
83 'contribution_id' => $contribution['id'],
84 'check_permissions' => TRUE,
85 ];
86 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'administer CiviCRM'];
87 $payment = $this->callAPIFailure('payment', 'get', $params, 'API permission check failed for Payment/get call; insufficient permission: require access CiviCRM and access CiviContribute');
88
89 array_push(CRM_Core_Config::singleton()->userPermissionClass->permissions, 'access CiviContribute');
90 $payment = $this->callAPISuccess('payment', 'get', $params);
91
92 $payment = $this->callAPIAndDocument('payment', 'get', $params, __FUNCTION__, __FILE__);
93 $this->assertEquals(1, $payment['count']);
94
95 $expectedResult = [
96 $contribution['id'] => [
97 'total_amount' => 100,
98 'trxn_id' => 23456,
99 'trxn_date' => '2010-01-20 00:00:00',
100 'contribution_id' => $contribution['id'],
101 'is_payment' => 1,
102 ],
103 ];
104 $this->checkPaymentResult($payment, $expectedResult);
105 $this->callAPISuccess('Contribution', 'Delete', [
106 'id' => $contribution['id'],
107 ]);
108 }
109
110 /**
111 * Retrieve Payment using trxn_id.
112 */
113 public function testGetPaymentWithTrxnID() {
114 $this->_individualId2 = $this->individualCreate();
115 $params1 = [
116 'contact_id' => $this->_individualId,
117 'trxn_id' => 111111,
118 'total_amount' => 10,
119 ];
120 $contributionID1 = $this->contributionCreate($params1);
121
122 $params2 = [
123 'contact_id' => $this->_individualId2,
124 'trxn_id' => 222222,
125 'total_amount' => 20,
126 ];
127 $contributionID2 = $this->contributionCreate($params2);
128
129 $paymentParams = ['trxn_id' => 111111];
130 $payment = $this->callAPISuccess('payment', 'get', $paymentParams);
131 $expectedResult = [
132 $payment['id'] => [
133 'total_amount' => 10,
134 'trxn_id' => 111111,
135 'status_id' => 1,
136 'is_payment' => 1,
137 'contribution_id' => $contributionID1,
138 ],
139 ];
140 $this->checkPaymentResult($payment, $expectedResult);
141
142 $paymentParams = ['trxn_id' => 222222];
143 $payment = $this->callAPISuccess('payment', 'get', $paymentParams);
144 $expectedResult = [
145 $payment['id'] => [
146 'total_amount' => 20,
147 'trxn_id' => 222222,
148 'status_id' => 1,
149 'is_payment' => 1,
150 'contribution_id' => $contributionID2,
151 ],
152 ];
153 $this->checkPaymentResult($payment, $expectedResult);
154 }
155
156 /**
157 * Test email receipt for partial payment.
158 */
159 public function testPaymentEmailReceipt() {
160 $mut = new CiviMailUtils($this);
161 list($lineItems, $contribution) = $this->createParticipantWithContribution();
162 $event = $this->callAPISuccess('Event', 'get', []);
163 $this->addLocationToEvent($event['id']);
164 $params = [
165 'contribution_id' => $contribution['id'],
166 'total_amount' => 50,
167 'check_number' => '345',
168 'trxn_date' => '2018-08-13 17:57:56',
169 ];
170 $payment = $this->callAPISuccess('payment', 'create', $params);
171 $this->checkPaymentResult($payment, [
172 $payment['id'] => [
173 'from_financial_account_id' => 7,
174 'to_financial_account_id' => 6,
175 'total_amount' => 50,
176 'status_id' => 1,
177 'is_payment' => 1,
178 ],
179 ]);
180
181 $this->callAPISuccess('Payment', 'sendconfirmation', ['id' => $payment['id']]);
182 $mut->assertSubjects(['Payment Receipt - Annual CiviCRM meet']);
183 $mut->checkMailLog([
184 'Dear Anthony,',
185 'Total Fees: $ 300.00',
186 'This Payment Amount: $ 50.00',
187 //150 was paid in the 1st payment.
188 'Balance Owed: $ 100.00',
189 'Event Information and Location',
190 'Paid By: Check',
191 'Check Number: 345',
192 'Transaction Date: August 13th, 2018 5:57 PM',
193 'event place',
194 'streety street',
195 ]);
196 $mut->stop();
197 $mut->clearMessages();
198 }
199
200 /**
201 * Test email receipt for partial payment.
202 *
203 * @throws \CRM_Core_Exception
204 */
205 public function testPaymentEmailReceiptFullyPaid() {
206 $mut = new CiviMailUtils($this);
207 list($lineItems, $contribution) = $this->createParticipantWithContribution();
208
209 $params = [
210 'contribution_id' => $contribution['id'],
211 'total_amount' => 150,
212 ];
213 $payment = $this->callAPISuccess('payment', 'create', $params);
214
215 $this->callAPISuccess('Payment', 'sendconfirmation', ['id' => $payment['id']]);
216 $mut->assertSubjects(['Payment Receipt - Annual CiviCRM meet', 'Registration Confirmation - Annual CiviCRM meet']);
217 $mut->checkMailLog([
218 'Dear Anthony,',
219 'A payment has been received.',
220 'Total Fees: $ 300.00',
221 'This Payment Amount: $ 150.00',
222 'Balance Owed: $ 0.00',
223 'Thank you for completing payment.',
224 ]);
225 $mut->stop();
226 $mut->clearMessages();
227 }
228
229 /**
230 * Test email receipt for partial payment.
231 *
232 * @dataProvider getThousandSeparators
233 *
234 * @param string $thousandSeparator
235 */
236 public function testRefundEmailReceipt($thousandSeparator) {
237 $this->setCurrencySeparators($thousandSeparator);
238 $decimalSeparator = ($thousandSeparator === ',' ? '.' : ',');
239 $mut = new CiviMailUtils($this);
240 list($lineItems, $contribution) = $this->createParticipantWithContribution();
241 $this->callAPISuccess('payment', 'create', [
242 'contribution_id' => $contribution['id'],
243 'total_amount' => 50,
244 'check_number' => '345',
245 'trxn_date' => '2018-08-13 17:57:56',
246 ]);
247
248 $payment = $this->callAPISuccess('payment', 'create', [
249 'contribution_id' => $contribution['id'],
250 'total_amount' => -30,
251 'trxn_date' => '2018-11-13 12:01:56',
252 'sequential' => TRUE,
253 ])['values'][0];
254
255 $expected = [
256 'from_financial_account_id' => 7,
257 'to_financial_account_id' => 6,
258 'total_amount' => -30,
259 'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_FinancialTrxn', 'status_id', 'Refunded'),
260 'is_payment' => 1,
261 ];
262 foreach ($expected as $key => $value) {
263 $this->assertEquals($expected[$key], $payment[$key], 'mismatch on key ' . $key);
264 }
265
266 $this->callAPISuccess('Payment', 'sendconfirmation', ['id' => $payment['id']]);
267 $mut->assertSubjects(['Refund Notification - Annual CiviCRM meet']);
268 $mut->checkMailLog([
269 'Dear Anthony,',
270 'A refund has been issued based on changes in your registration selections.',
271 'Total Fees: $ 300' . $decimalSeparator . '00',
272 'Refund Amount: $ -30' . $decimalSeparator . '00',
273 'Event Information and Location',
274 'Paid By: Check',
275 'Transaction Date: November 13th, 2018 12:01 PM',
276 'You Paid: $ 170' . $decimalSeparator . '00',
277 ]);
278 $mut->stop();
279 $mut->clearMessages();
280 }
281
282 /**
283 * Test create payment api with no line item in params
284 */
285 public function testCreatePaymentNoLineItems() {
286 list($lineItems, $contribution) = $this->createParticipantWithContribution();
287
288 //Create partial payment
289 $params = [
290 'contribution_id' => $contribution['id'],
291 'total_amount' => 50,
292 ];
293 $payment = $this->callAPIAndDocument('payment', 'create', $params, __FUNCTION__, __FILE__);
294 $expectedResult = [
295 $payment['id'] => [
296 'from_financial_account_id' => 7,
297 'to_financial_account_id' => 6,
298 'total_amount' => 50,
299 'status_id' => 1,
300 'is_payment' => 1,
301 ],
302 ];
303 $this->checkPaymentResult($payment, $expectedResult);
304
305 // Check entity financial trxn created properly
306 $params = [
307 'entity_id' => $contribution['id'],
308 'entity_table' => 'civicrm_contribution',
309 'financial_trxn_id' => $payment['id'],
310 ];
311
312 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
313
314 $this->assertEquals($eft['values'][$eft['id']]['amount'], 50);
315
316 $params = [
317 'entity_table' => 'civicrm_financial_item',
318 'financial_trxn_id' => $payment['id'],
319 ];
320 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
321 $amounts = [33.33, 16.67];
322 foreach ($eft['values'] as $value) {
323 $this->assertEquals($value['amount'], array_pop($amounts));
324 }
325
326 // Now create payment to complete total amount of contribution
327 $params = [
328 'contribution_id' => $contribution['id'],
329 'total_amount' => 100,
330 ];
331 $payment = $this->callAPISuccess('payment', 'create', $params);
332 $expectedResult = [
333 $payment['id'] => [
334 'from_financial_account_id' => 7,
335 'to_financial_account_id' => 6,
336 'total_amount' => 100,
337 'status_id' => 1,
338 'is_payment' => 1,
339 ],
340 ];
341 $this->checkPaymentResult($payment, $expectedResult);
342 $params = [
343 'entity_table' => 'civicrm_financial_item',
344 'financial_trxn_id' => $payment['id'],
345 ];
346 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
347 $amounts = [66.67, 33.33];
348 foreach ($eft['values'] as $value) {
349 $this->assertEquals($value['amount'], array_pop($amounts));
350 }
351 // Check contribution for completed status
352 $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id']]);
353
354 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Completed');
355 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 300.00);
356 $paymentParticipant = [
357 'contribution_id' => $contribution['id'],
358 ];
359 $participantPayment = $this->callAPISuccess('ParticipantPayment', 'getsingle', $paymentParticipant);
360 $participant = $this->callAPISuccess('participant', 'get', ['id' => $participantPayment['participant_id']]);
361 $this->assertEquals($participant['values'][$participant['id']]['participant_status'], 'Registered');
362 $this->callAPISuccess('Contribution', 'Delete', [
363 'id' => $contribution['id'],
364 ]);
365 }
366
367 /**
368 * Function to assert db values
369 */
370 public function checkPaymentResult($payment, $expectedResult) {
371 foreach ($expectedResult[$payment['id']] as $key => $value) {
372 $this->assertEquals($payment['values'][$payment['id']][$key], $value, 'mismatch on ' . $key);
373 }
374 }
375
376 /**
377 * Test create payment api with line item in params
378 */
379 public function testCreatePaymentLineItems() {
380 list($lineItems, $contribution) = $this->createParticipantWithContribution();
381 $lineItems = $this->callAPISuccess('LineItem', 'get', ['contribution_id' => $contribution['id']]);
382
383 //Create partial payment by passing line item array is params
384 $params = [
385 'contribution_id' => $contribution['id'],
386 'total_amount' => 50,
387 ];
388 $amounts = [40, 10];
389 foreach ($lineItems['values'] as $id => $ignore) {
390 $params['line_item'][] = [$id => array_pop($amounts)];
391 }
392 $payment = $this->callAPIAndDocument('payment', 'create', $params, __FUNCTION__, __FILE__, 'Payment with line item', 'CreatePaymentWithLineItems');
393 $expectedResult = [
394 $payment['id'] => [
395 'from_financial_account_id' => 7,
396 'to_financial_account_id' => 6,
397 'total_amount' => 50,
398 'status_id' => 1,
399 'is_payment' => 1,
400 ],
401 ];
402 $this->checkPaymentResult($payment, $expectedResult);
403
404 // Check entity financial trxn created properly
405 $params = [
406 'entity_id' => $contribution['id'],
407 'entity_table' => 'civicrm_contribution',
408 'financial_trxn_id' => $payment['id'],
409 ];
410
411 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
412
413 $this->assertEquals($eft['values'][$eft['id']]['amount'], 50);
414
415 $params = [
416 'entity_table' => 'civicrm_financial_item',
417 'financial_trxn_id' => $payment['id'],
418 ];
419 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
420 $amounts = [40, 10];
421 foreach ($eft['values'] as $value) {
422 $this->assertEquals($value['amount'], array_pop($amounts));
423 }
424
425 // Now create payment to complete total amount of contribution
426 $params = [
427 'contribution_id' => $contribution['id'],
428 'total_amount' => 100,
429 ];
430 $amounts = [80, 20];
431 foreach ($lineItems['values'] as $id => $ignore) {
432 $params['line_item'][] = [$id => array_pop($amounts)];
433 }
434 $payment = $this->callAPISuccess('payment', 'create', $params);
435 $expectedResult = [
436 $payment['id'] => [
437 'from_financial_account_id' => 7,
438 'to_financial_account_id' => 6,
439 'total_amount' => 100,
440 'status_id' => 1,
441 'is_payment' => 1,
442 ],
443 ];
444 $this->checkPaymentResult($payment, $expectedResult);
445 $params = [
446 'entity_table' => 'civicrm_financial_item',
447 'financial_trxn_id' => $payment['id'],
448 ];
449 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
450 $amounts = [80, 20];
451 foreach ($eft['values'] as $value) {
452 $this->assertEquals($value['amount'], array_pop($amounts));
453 }
454 // Check contribution for completed status
455 $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id']]);
456
457 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Completed');
458 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 300.00);
459 $paymentParticipant = [
460 'contribution_id' => $contribution['id'],
461 ];
462 $participantPayment = $this->callAPISuccess('ParticipantPayment', 'getsingle', $paymentParticipant);
463 $participant = $this->callAPISuccess('participant', 'get', ['id' => $participantPayment['participant_id']]);
464 $this->assertEquals($participant['values'][$participant['id']]['participant_status'], 'Registered');
465 $this->callAPISuccess('Contribution', 'Delete', [
466 'id' => $contribution['id'],
467 ]);
468 }
469
470 /**
471 * Test cancel payment api
472 */
473 public function testCancelPayment() {
474 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['administer CiviCRM', 'access CiviContribute'];
475 list($lineItems, $contribution) = $this->createParticipantWithContribution();
476
477 $params = [
478 'contribution_id' => $contribution['id'],
479 ];
480
481 $payment = $this->callAPISuccess('payment', 'get', $params);
482 $this->assertEquals(1, $payment['count']);
483
484 $cancelParams = [
485 'id' => $payment['id'],
486 'check_permissions' => TRUE,
487 ];
488 $payment = $this->callAPIFailure('payment', 'cancel', $cancelParams, 'API permission check failed for Payment/cancel call; insufficient permission: require access CiviCRM and access CiviContribute and edit contributions');
489
490 array_push(CRM_Core_Config::singleton()->userPermissionClass->permissions, 'access CiviCRM', 'edit contributions');
491
492 $this->callAPIAndDocument('payment', 'cancel', $cancelParams, __FUNCTION__, __FILE__);
493
494 $payment = $this->callAPISuccess('payment', 'get', $params);
495 $this->assertEquals(2, $payment['count']);
496 $amounts = [-150.00, 150.00];
497 foreach ($payment['values'] as $value) {
498 $this->assertEquals($value['total_amount'], array_pop($amounts), 'Mismatch total amount');
499 }
500
501 $this->callAPISuccess('Contribution', 'Delete', [
502 'id' => $contribution['id'],
503 ]);
504 }
505
506 /**
507 * Test delete payment api
508 */
509 public function testDeletePayment() {
510 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['administer CiviCRM', 'access CiviContribute'];
511 list($lineItems, $contribution) = $this->createParticipantWithContribution();
512
513 $params = [
514 'contribution_id' => $contribution['id'],
515 ];
516
517 $payment = $this->callAPISuccess('payment', 'get', $params);
518 $this->assertEquals(1, $payment['count']);
519
520 $deleteParams = [
521 'id' => $payment['id'],
522 'check_permissions' => TRUE,
523 ];
524 $payment = $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');
525
526 array_push(CRM_Core_Config::singleton()->userPermissionClass->permissions, 'access CiviCRM', 'delete in CiviContribute');
527 $this->callAPIAndDocument('payment', 'delete', $deleteParams, __FUNCTION__, __FILE__);
528
529 $payment = $this->callAPISuccess('payment', 'get', $params);
530 $this->assertEquals(0, $payment['count']);
531
532 $this->callAPISuccess('Contribution', 'Delete', [
533 'id' => $contribution['id'],
534 ]);
535 }
536
537 /**
538 * Test update payment api.
539 *
540 * 1) create a contribution for $300 with a partial payment of $150
541 * - this results in 2 financial transactions. The accounts receivable transaction is linked
542 * via entity_financial_trxns to the 2 line items. The $150 payment is not linked to the line items
543 * so the line items are fully allocated even though they are only half paid.
544 *
545 * 2) add a payment of $50 -
546 * This payment transaction IS linked to the line items so $350 of the $300 in line items is allocated
547 * but $200 is paid
548 *
549 * 3) update that payment to be $100
550 * This results in a negative and a positive payment ($50 & $100) - the negative payment results in
551 * financial_items but the positive payment does not.
552 *
553 * The final result is we have
554 * - 1 partly paid contribution of $300
555 * - payment financial_trxns totalling $250
556 * - 1 Accounts receivable financial_trxn totalling $300
557 * - 2 financial items totalling $300 linked to the Accounts receivable financial_trxn
558 * - 6 entries in the civicrm_entity_financial_trxn linked to line items - totalling $450.
559 * - 5 entries in the civicrm_entity_financial_trxn linked to contributions - totalling $550.
560 */
561 public function testUpdatePayment() {
562 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['administer CiviCRM', 'access CiviContribute', 'edit contributions'];
563 list($lineItems, $contribution) = $this->createParticipantWithContribution();
564
565 //Create partial payment by passing line item array is params
566 $params = [
567 'contribution_id' => $contribution['id'],
568 'total_amount' => 50,
569 ];
570
571 $payment = $this->callAPISuccess('payment', 'create', $params);
572 $expectedResult = [
573 $payment['id'] => [
574 'from_financial_account_id' => 7,
575 'to_financial_account_id' => 6,
576 'total_amount' => 50,
577 'status_id' => 1,
578 'is_payment' => 1,
579 ],
580 ];
581 $this->checkPaymentResult($payment, $expectedResult);
582
583 $params = [
584 'entity_table' => 'civicrm_financial_item',
585 'financial_trxn_id' => $payment['id'],
586 ];
587 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
588 $amounts = [33.33, 16.67];
589 foreach ($eft['values'] as $value) {
590 $this->assertEquals($value['amount'], array_pop($amounts));
591 }
592
593 // update the amount for payment
594 $params = [
595 'contribution_id' => $contribution['id'],
596 'total_amount' => 100,
597 'id' => $payment['id'],
598 'check_permissions' => TRUE,
599 ];
600 // @todo - move this permissions test to it's own test - it just confuses here.
601 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['administer CiviCRM', 'access CiviContribute'];
602 $this->callAPIFailure('payment', 'create', $params, 'API permission check failed for Payment/create call; insufficient permission: require access CiviCRM and access CiviContribute and edit contributions');
603
604 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['administer CiviCRM', 'access CiviContribute', 'access CiviCRM', 'edit contributions'];
605 $payment = $this->callAPIAndDocument('payment', 'create', $params, __FUNCTION__, __FILE__, 'Update Payment', 'UpdatePayment');
606
607 // Check for proportional cancelled payment against lineitems.
608 $minParams = [
609 'entity_table' => 'civicrm_financial_item',
610 'financial_trxn_id' => $payment['id'] - 1,
611 ];
612
613 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $minParams);
614 $amounts = [-33.33, -16.67];
615
616 foreach ($eft['values'] as $value) {
617 $this->assertEquals($value['amount'], array_pop($amounts));
618 }
619
620 // Check for proportional updated payment against lineitems.
621 $params = [
622 'entity_table' => 'civicrm_financial_item',
623 'financial_trxn_id' => $payment['id'],
624 ];
625 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
626 $amounts = [66.67, 33.33];
627 foreach ($eft['values'] as $value) {
628 $this->assertEquals($value['amount'], array_pop($amounts));
629 }
630 $items = $this->callAPISuccess('FinancialItem', 'get', [])['values'];
631 $this->assertCount(2, $items);
632 $itemSum = 0;
633 foreach ($items as $item) {
634 $this->assertEquals('civicrm_line_item', $item['entity_table']);
635 $itemSum += $item['amount'];
636 }
637 $this->assertEquals(300, $itemSum);
638
639 $params = [
640 'contribution_id' => $contribution['id'],
641 ];
642 $payment = $this->callAPISuccess('payment', 'get', $params);
643 $amounts = [100.00, -50.00, 50.00, 150.00];
644 foreach ($payment['values'] as $value) {
645 $amount = array_pop($amounts);
646 $this->assertEquals($value['total_amount'], $amount, 'Mismatch total amount');
647
648 // Check entity financial trxn created properly
649 $params = [
650 'entity_id' => $contribution['id'],
651 'entity_table' => 'civicrm_contribution',
652 'financial_trxn_id' => $value['id'],
653 ];
654 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
655 $this->assertEquals($eft['values'][$eft['id']]['amount'], $amount);
656 }
657
658 $this->callAPISuccess('Contribution', 'Delete', [
659 'id' => $contribution['id'],
660 ]);
661 }
662
663 /**
664 * Test create payment api for paylater contribution
665 */
666 public function testCreatePaymentPayLater() {
667 $this->createLoggedInUser();
668 $contributionParams = [
669 'total_amount' => 100,
670 'currency' => 'USD',
671 'contact_id' => $this->_individualId,
672 'financial_type_id' => 1,
673 'contribution_status_id' => 2,
674 'is_pay_later' => 1,
675 ];
676 $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams);
677 //add payment for pay later transaction
678 $params = [
679 'contribution_id' => $contribution['id'],
680 'total_amount' => 100,
681 ];
682 $payment = $this->callAPISuccess('Payment', 'create', $params);
683 $expectedResult = [
684 $payment['id'] => [
685 'from_financial_account_id' => 7,
686 'to_financial_account_id' => 6,
687 'total_amount' => 100,
688 'status_id' => 1,
689 'is_payment' => 1,
690 ],
691 ];
692 $this->checkPaymentResult($payment, $expectedResult);
693 // Check entity financial trxn created properly
694 $params = [
695 'entity_id' => $contribution['id'],
696 'entity_table' => 'civicrm_contribution',
697 'financial_trxn_id' => $payment['id'],
698 ];
699 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
700 $this->assertEquals($eft['values'][$eft['id']]['amount'], 100);
701 $params = [
702 'entity_table' => 'civicrm_financial_item',
703 'financial_trxn_id' => $payment['id'],
704 ];
705 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
706 $this->assertEquals($eft['values'][$eft['id']]['amount'], 100);
707 // Check contribution for completed status
708 $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id']]);
709 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Completed');
710 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00);
711 $this->callAPISuccess('Contribution', 'Delete', [
712 'id' => $contribution['id'],
713 ]);
714 }
715
716 /**
717 * Test create payment api for pay later contribution with partial payment.
718 *
719 * @throws \Exception
720 */
721 public function testCreatePaymentPayLaterPartialPayment() {
722 $this->createLoggedInUser();
723 $contributionParams = [
724 'total_amount' => 100,
725 'currency' => 'USD',
726 'contact_id' => $this->_individualId,
727 'financial_type_id' => 1,
728 'contribution_status_id' => 2,
729 'is_pay_later' => 1,
730 ];
731 $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams);
732 //Create partial payment
733 $params = [
734 'contribution_id' => $contribution['id'],
735 'total_amount' => 60,
736 ];
737 $payment = $this->callAPISuccess('Payment', 'create', $params);
738 $expectedResult = [
739 $payment['id'] => [
740 'total_amount' => 60,
741 'status_id' => 1,
742 'is_payment' => 1,
743 ],
744 ];
745 $this->checkPaymentResult($payment, $expectedResult);
746 // Check entity financial trxn created properly
747 $params = [
748 'entity_id' => $contribution['id'],
749 'entity_table' => 'civicrm_contribution',
750 'financial_trxn_id' => $payment['id'],
751 ];
752 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
753 $this->assertEquals($eft['values'][$eft['id']]['amount'], 60);
754 $params = [
755 'entity_table' => 'civicrm_financial_item',
756 'financial_trxn_id' => $payment['id'],
757 ];
758 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
759 $this->assertEquals($eft['values'][$eft['id']]['amount'], 60);
760 $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id']]);
761 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Partially paid');
762 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00);
763 //Create full payment
764 $params = [
765 'contribution_id' => $contribution['id'],
766 'total_amount' => 40,
767 ];
768 // Rename the 'completed' status label first to check that we are not using the labels!
769 $this->callAPISuccess('OptionValue', 'get', ['name' => 'Completed', 'option_group_id' => 'contribution_status', 'api.OptionValue.create' => ['label' => 'Unicorn']]);
770 $payment = $this->callAPISuccess('Payment', 'create', $params);
771 $expectedResult = [
772 $payment['id'] => [
773 'from_financial_account_id' => 7,
774 'to_financial_account_id' => 6,
775 'total_amount' => 40,
776 'status_id' => 1,
777 'is_payment' => 1,
778 ],
779 ];
780 $this->checkPaymentResult($payment, $expectedResult);
781 // Check entity financial trxn created properly
782 $params = [
783 'entity_id' => $contribution['id'],
784 'entity_table' => 'civicrm_contribution',
785 'financial_trxn_id' => $payment['id'],
786 ];
787 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
788 $this->assertEquals($eft['values'][$eft['id']]['amount'], 40);
789 $params = [
790 'entity_table' => 'civicrm_financial_item',
791 'financial_trxn_id' => $payment['id'],
792 ];
793 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
794 $this->assertEquals($eft['values'][$eft['id']]['amount'], 40);
795 // Check contribution for completed status
796 $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id']]);
797 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Unicorn');
798 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00);
799 $this->callAPISuccess('Contribution', 'Delete', [
800 'id' => $contribution['id'],
801 ]);
802 $this->callAPISuccess('OptionValue', 'get', ['name' => 'Completed', 'option_group_id' => 'contribution_status', 'api.OptionValue.create' => ['label' => 'Completed']]);
803 $this->callAPISuccessGetCount('Activity', ['target_contact_id' => $this->_individualId, 'activity_type_id' => 'Payment'], 2);
804 }
805
806 /**
807 * Add a location to our event.
808 *
809 * @param int $eventID
810 */
811 protected function addLocationToEvent($eventID) {
812 $addressParams = [
813 'name' => 'event place',
814 'street_address' => 'streety street',
815 'location_type_id' => 1,
816 'is_primary' => 1,
817 ];
818 // api requires contact_id - perhaps incorrectly but use add to get past that.
819 $address = CRM_Core_BAO_Address::add($addressParams);
820
821 $location = $this->callAPISuccess('LocBlock', 'create', ['address_id' => $address->id]);
822 $this->callAPISuccess('Event', 'create', [
823 'id' => $eventID,
824 'loc_block_id' => $location['id'],
825 'is_show_location' => TRUE,
826 ]);
827 }
828
829 }