Include Displayname in some workflow templates
[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 - Mr. Anthony Anderson II']);
183 $mut->checkMailLog([
184 'From: "FIXME" <info@EXAMPLE.ORG>',
185 'Dear Anthony,',
186 'Total Fees: $ 300.00',
187 'This Payment Amount: $ 50.00',
188 //150 was paid in the 1st payment.
189 'Balance Owed: $ 100.00',
190 'Event Information and Location',
191 'Paid By: Check',
192 'Check Number: 345',
193 'Transaction Date: August 13th, 2018 5:57 PM',
194 'event place',
195 'streety street',
196 ]);
197 $mut->stop();
198 $mut->clearMessages();
199 }
200
201 /**
202 * Test email receipt for partial payment.
203 *
204 * @throws \CRM_Core_Exception
205 */
206 public function testPaymentEmailReceiptFullyPaid() {
207 $mut = new CiviMailUtils($this);
208 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviContribute', 'edit contributions', 'access CiviCRM'];
209 list($lineItems, $contribution) = $this->createParticipantWithContribution();
210
211 $params = [
212 'contribution_id' => $contribution['id'],
213 'total_amount' => 150,
214 ];
215 $payment = $this->callAPISuccess('payment', 'create', $params);
216
217 // Here we set the email to an invalid email & use check_permissions, domain email should be used.
218 $email = $this->callAPISuccess('Email', 'create', ['contact_id' => 1, 'email' => 'bob@example.com']);
219 $this->callAPISuccess('Payment', 'sendconfirmation', ['id' => $payment['id'], 'from' => $email['id'], 'check_permissions' => 1]);
220 $mut->assertSubjects(['Payment Receipt - Annual CiviCRM meet - Mr. Anthony Anderson II', 'Registration Confirmation - Annual CiviCRM meet - Mr. Anthony Anderson II']);
221 $mut->checkMailLog([
222 'From: "FIXME" <info@EXAMPLE.ORG>',
223 'Dear Anthony,',
224 'A payment has been received.',
225 'Total Fees: $ 300.00',
226 'This Payment Amount: $ 150.00',
227 'Balance Owed: $ 0.00',
228 'Thank you for completing this payment.',
229 ]);
230 $mut->stop();
231 $mut->clearMessages();
232 }
233
234 /**
235 * Test email receipt for partial payment.
236 *
237 * @dataProvider getThousandSeparators
238 *
239 * @param string $thousandSeparator
240 */
241 public function testRefundEmailReceipt($thousandSeparator) {
242 $this->setCurrencySeparators($thousandSeparator);
243 $decimalSeparator = ($thousandSeparator === ',' ? '.' : ',');
244 $mut = new CiviMailUtils($this);
245 list($lineItems, $contribution) = $this->createParticipantWithContribution();
246 $this->callAPISuccess('payment', 'create', [
247 'contribution_id' => $contribution['id'],
248 'total_amount' => 50,
249 'check_number' => '345',
250 'trxn_date' => '2018-08-13 17:57:56',
251 ]);
252
253 $payment = $this->callAPISuccess('payment', 'create', [
254 'contribution_id' => $contribution['id'],
255 'total_amount' => -30,
256 'trxn_date' => '2018-11-13 12:01:56',
257 'sequential' => TRUE,
258 ])['values'][0];
259
260 $expected = [
261 'from_financial_account_id' => 7,
262 'to_financial_account_id' => 6,
263 'total_amount' => -30,
264 'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_FinancialTrxn', 'status_id', 'Refunded'),
265 'is_payment' => 1,
266 ];
267 foreach ($expected as $key => $value) {
268 $this->assertEquals($expected[$key], $payment[$key], 'mismatch on key ' . $key);
269 }
270
271 $this->callAPISuccess('Payment', 'sendconfirmation', ['id' => $payment['id']]);
272 $mut->assertSubjects(['Refund Notification - Annual CiviCRM meet - Mr. Anthony Anderson II']);
273 $mut->checkMailLog([
274 'Dear Anthony,',
275 'A refund has been issued based on changes in your registration selections.',
276 'Total Fees: $ 300' . $decimalSeparator . '00',
277 'Refund Amount: $ -30' . $decimalSeparator . '00',
278 'Event Information and Location',
279 'Paid By: Check',
280 'Transaction Date: November 13th, 2018 12:01 PM',
281 'You Paid: $ 170' . $decimalSeparator . '00',
282 ]);
283 $mut->stop();
284 $mut->clearMessages();
285 }
286
287 /**
288 * Test create payment api with no line item in params
289 */
290 public function testCreatePaymentNoLineItems() {
291 list($lineItems, $contribution) = $this->createParticipantWithContribution();
292
293 //Create partial payment
294 $params = [
295 'contribution_id' => $contribution['id'],
296 'total_amount' => 50,
297 ];
298 $payment = $this->callAPIAndDocument('payment', 'create', $params, __FUNCTION__, __FILE__);
299 $expectedResult = [
300 $payment['id'] => [
301 'from_financial_account_id' => 7,
302 'to_financial_account_id' => 6,
303 'total_amount' => 50,
304 'status_id' => 1,
305 'is_payment' => 1,
306 ],
307 ];
308 $this->checkPaymentResult($payment, $expectedResult);
309
310 // Check entity financial trxn created properly
311 $params = [
312 'entity_id' => $contribution['id'],
313 'entity_table' => 'civicrm_contribution',
314 'financial_trxn_id' => $payment['id'],
315 ];
316
317 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
318
319 $this->assertEquals($eft['values'][$eft['id']]['amount'], 50);
320
321 $params = [
322 'entity_table' => 'civicrm_financial_item',
323 'financial_trxn_id' => $payment['id'],
324 ];
325 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
326 $amounts = [33.33, 16.67];
327 foreach ($eft['values'] as $value) {
328 $this->assertEquals($value['amount'], array_pop($amounts));
329 }
330
331 // Now create payment to complete total amount of contribution
332 $params = [
333 'contribution_id' => $contribution['id'],
334 'total_amount' => 100,
335 ];
336 $payment = $this->callAPISuccess('payment', 'create', $params);
337 $expectedResult = [
338 $payment['id'] => [
339 'from_financial_account_id' => 7,
340 'to_financial_account_id' => 6,
341 'total_amount' => 100,
342 'status_id' => 1,
343 'is_payment' => 1,
344 ],
345 ];
346 $this->checkPaymentResult($payment, $expectedResult);
347 $params = [
348 'entity_table' => 'civicrm_financial_item',
349 'financial_trxn_id' => $payment['id'],
350 ];
351 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
352 $amounts = [66.67, 33.33];
353 foreach ($eft['values'] as $value) {
354 $this->assertEquals($value['amount'], array_pop($amounts));
355 }
356 // Check contribution for completed status
357 $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id']]);
358
359 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Completed');
360 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 300.00);
361 $paymentParticipant = [
362 'contribution_id' => $contribution['id'],
363 ];
364 $participantPayment = $this->callAPISuccess('ParticipantPayment', 'getsingle', $paymentParticipant);
365 $participant = $this->callAPISuccess('participant', 'get', ['id' => $participantPayment['participant_id']]);
366 $this->assertEquals($participant['values'][$participant['id']]['participant_status'], 'Registered');
367 $this->callAPISuccess('Contribution', 'Delete', [
368 'id' => $contribution['id'],
369 ]);
370 }
371
372 /**
373 * Function to assert db values
374 *
375 * @throws \CRM_Core_Exception
376 */
377 public function checkPaymentResult($payment, $expectedResult) {
378 $refreshedPayment = $this->callAPISuccessGetSingle('Payment', ['financial_trxn_id' => $payment['id']]);
379 foreach ($expectedResult[$payment['id']] as $key => $value) {
380 $this->assertEquals($refreshedPayment[$key], $value, 'mismatch on ' . $key); $this->assertEquals($refreshedPayment[$key], $value, 'mismatch on ' . $key);
381 }
382 }
383
384 /**
385 * Test create payment api with line item in params
386 */
387 public function testCreatePaymentLineItems() {
388 list($lineItems, $contribution) = $this->createParticipantWithContribution();
389 $lineItems = $this->callAPISuccess('LineItem', 'get', ['contribution_id' => $contribution['id']]);
390
391 //Create partial payment by passing line item array is params
392 $params = [
393 'contribution_id' => $contribution['id'],
394 'total_amount' => 50,
395 ];
396 $amounts = [40, 10];
397 foreach ($lineItems['values'] as $id => $ignore) {
398 $params['line_item'][] = [$id => array_pop($amounts)];
399 }
400 $payment = $this->callAPIAndDocument('payment', 'create', $params, __FUNCTION__, __FILE__, 'Payment with line item', 'CreatePaymentWithLineItems');
401 $expectedResult = [
402 $payment['id'] => [
403 'from_financial_account_id' => 7,
404 'to_financial_account_id' => 6,
405 'total_amount' => 50,
406 'status_id' => 1,
407 'is_payment' => 1,
408 ],
409 ];
410 $this->checkPaymentResult($payment, $expectedResult);
411
412 // Check entity financial trxn created properly
413 $params = [
414 'entity_id' => $contribution['id'],
415 'entity_table' => 'civicrm_contribution',
416 'financial_trxn_id' => $payment['id'],
417 ];
418
419 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
420
421 $this->assertEquals($eft['values'][$eft['id']]['amount'], 50);
422
423 $params = [
424 'entity_table' => 'civicrm_financial_item',
425 'financial_trxn_id' => $payment['id'],
426 ];
427 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
428 $amounts = [40, 10];
429 foreach ($eft['values'] as $value) {
430 $this->assertEquals($value['amount'], array_pop($amounts));
431 }
432
433 // Now create payment to complete total amount of contribution
434 $params = [
435 'contribution_id' => $contribution['id'],
436 'total_amount' => 100,
437 ];
438 $amounts = [80, 20];
439 foreach ($lineItems['values'] as $id => $ignore) {
440 $params['line_item'][] = [$id => array_pop($amounts)];
441 }
442 $payment = $this->callAPISuccess('payment', 'create', $params);
443 $expectedResult = [
444 $payment['id'] => [
445 'from_financial_account_id' => 7,
446 'to_financial_account_id' => 6,
447 'total_amount' => 100,
448 'status_id' => 1,
449 'is_payment' => 1,
450 ],
451 ];
452 $this->checkPaymentResult($payment, $expectedResult);
453 $params = [
454 'entity_table' => 'civicrm_financial_item',
455 'financial_trxn_id' => $payment['id'],
456 ];
457 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
458 $amounts = [80, 20];
459 foreach ($eft['values'] as $value) {
460 $this->assertEquals($value['amount'], array_pop($amounts));
461 }
462 // Check contribution for completed status
463 $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id']]);
464
465 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Completed');
466 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 300.00);
467 $paymentParticipant = [
468 'contribution_id' => $contribution['id'],
469 ];
470 $participantPayment = $this->callAPISuccess('ParticipantPayment', 'getsingle', $paymentParticipant);
471 $participant = $this->callAPISuccess('participant', 'get', ['id' => $participantPayment['participant_id']]);
472 $this->assertEquals($participant['values'][$participant['id']]['participant_status'], 'Registered');
473 $this->callAPISuccess('Contribution', 'Delete', [
474 'id' => $contribution['id'],
475 ]);
476 }
477
478 /**
479 * Test cancel payment api
480 */
481 public function testCancelPayment() {
482 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['administer CiviCRM', 'access CiviContribute'];
483 list($lineItems, $contribution) = $this->createParticipantWithContribution();
484
485 $params = [
486 'contribution_id' => $contribution['id'],
487 ];
488
489 $payment = $this->callAPISuccess('payment', 'get', $params);
490 $this->assertEquals(1, $payment['count']);
491
492 $cancelParams = [
493 'id' => $payment['id'],
494 'check_permissions' => TRUE,
495 ];
496 $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');
497
498 array_push(CRM_Core_Config::singleton()->userPermissionClass->permissions, 'access CiviCRM', 'edit contributions');
499
500 $this->callAPIAndDocument('payment', 'cancel', $cancelParams, __FUNCTION__, __FILE__);
501
502 $payment = $this->callAPISuccess('payment', 'get', $params);
503 $this->assertEquals(2, $payment['count']);
504 $amounts = [-150.00, 150.00];
505 foreach ($payment['values'] as $value) {
506 $this->assertEquals($value['total_amount'], array_pop($amounts), 'Mismatch total amount');
507 }
508
509 $this->callAPISuccess('Contribution', 'Delete', [
510 'id' => $contribution['id'],
511 ]);
512 }
513
514 /**
515 * Test delete payment api
516 */
517 public function testDeletePayment() {
518 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['administer CiviCRM', 'access CiviContribute'];
519 list($lineItems, $contribution) = $this->createParticipantWithContribution();
520
521 $params = [
522 'contribution_id' => $contribution['id'],
523 ];
524
525 $payment = $this->callAPISuccess('payment', 'get', $params);
526 $this->assertEquals(1, $payment['count']);
527
528 $deleteParams = [
529 'id' => $payment['id'],
530 'check_permissions' => TRUE,
531 ];
532 $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');
533
534 array_push(CRM_Core_Config::singleton()->userPermissionClass->permissions, 'access CiviCRM', 'delete in CiviContribute');
535 $this->callAPIAndDocument('payment', 'delete', $deleteParams, __FUNCTION__, __FILE__);
536
537 $payment = $this->callAPISuccess('payment', 'get', $params);
538 $this->assertEquals(0, $payment['count']);
539
540 $this->callAPISuccess('Contribution', 'Delete', [
541 'id' => $contribution['id'],
542 ]);
543 }
544
545 /**
546 * Test update payment api.
547 *
548 * 1) create a contribution for $300 with a partial payment of $150
549 * - this results in 2 financial transactions. The accounts receivable transaction is linked
550 * via entity_financial_trxns to the 2 line items. The $150 payment is not linked to the line items
551 * so the line items are fully allocated even though they are only half paid.
552 *
553 * 2) add a payment of $50 -
554 * This payment transaction IS linked to the line items so $350 of the $300 in line items is allocated
555 * but $200 is paid
556 *
557 * 3) update that payment to be $100
558 * This results in a negative and a positive payment ($50 & $100) - the negative payment results in
559 * financial_items but the positive payment does not.
560 *
561 * The final result is we have
562 * - 1 partly paid contribution of $300
563 * - payment financial_trxns totalling $250
564 * - 1 Accounts receivable financial_trxn totalling $300
565 * - 2 financial items totalling $300 linked to the Accounts receivable financial_trxn
566 * - 6 entries in the civicrm_entity_financial_trxn linked to line items - totalling $450.
567 * - 5 entries in the civicrm_entity_financial_trxn linked to contributions - totalling $550.
568 */
569 public function testUpdatePayment() {
570 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['administer CiviCRM', 'access CiviContribute', 'edit contributions'];
571 list($lineItems, $contribution) = $this->createParticipantWithContribution();
572
573 //Create partial payment by passing line item array is params
574 $params = [
575 'contribution_id' => $contribution['id'],
576 'total_amount' => 50,
577 ];
578
579 $payment = $this->callAPISuccess('payment', 'create', $params);
580 $expectedResult = [
581 $payment['id'] => [
582 'from_financial_account_id' => 7,
583 'to_financial_account_id' => 6,
584 'total_amount' => 50,
585 'status_id' => 1,
586 'is_payment' => 1,
587 ],
588 ];
589 $this->checkPaymentResult($payment, $expectedResult);
590
591 $params = [
592 'entity_table' => 'civicrm_financial_item',
593 'financial_trxn_id' => $payment['id'],
594 ];
595 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
596 $amounts = [33.33, 16.67];
597 foreach ($eft['values'] as $value) {
598 $this->assertEquals($value['amount'], array_pop($amounts));
599 }
600
601 // update the amount for payment
602 $params = [
603 'contribution_id' => $contribution['id'],
604 'total_amount' => 100,
605 'id' => $payment['id'],
606 'check_permissions' => TRUE,
607 ];
608 // @todo - move this permissions test to it's own test - it just confuses here.
609 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['administer CiviCRM', 'access CiviContribute'];
610 $this->callAPIFailure('payment', 'create', $params, 'API permission check failed for Payment/create call; insufficient permission: require access CiviCRM and access CiviContribute and edit contributions');
611
612 CRM_Core_Config::singleton()->userPermissionClass->permissions = ['administer CiviCRM', 'access CiviContribute', 'access CiviCRM', 'edit contributions'];
613 $payment = $this->callAPIAndDocument('payment', 'create', $params, __FUNCTION__, __FILE__, 'Update Payment', 'UpdatePayment');
614
615 // Check for proportional cancelled payment against lineitems.
616 $minParams = [
617 'entity_table' => 'civicrm_financial_item',
618 'financial_trxn_id' => $payment['id'] - 1,
619 ];
620
621 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $minParams);
622 $amounts = [-33.33, -16.67];
623
624 foreach ($eft['values'] as $value) {
625 $this->assertEquals($value['amount'], array_pop($amounts));
626 }
627
628 // Check for proportional updated payment against lineitems.
629 $params = [
630 'entity_table' => 'civicrm_financial_item',
631 'financial_trxn_id' => $payment['id'],
632 ];
633 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
634 $amounts = [66.67, 33.33];
635 foreach ($eft['values'] as $value) {
636 $this->assertEquals($value['amount'], array_pop($amounts));
637 }
638 $items = $this->callAPISuccess('FinancialItem', 'get', [])['values'];
639 $this->assertCount(2, $items);
640 $itemSum = 0;
641 foreach ($items as $item) {
642 $this->assertEquals('civicrm_line_item', $item['entity_table']);
643 $itemSum += $item['amount'];
644 }
645 $this->assertEquals(300, $itemSum);
646
647 $params = [
648 'contribution_id' => $contribution['id'],
649 ];
650 $payment = $this->callAPISuccess('payment', 'get', $params);
651 $amounts = [100.00, -50.00, 50.00, 150.00];
652 foreach ($payment['values'] as $value) {
653 $amount = array_pop($amounts);
654 $this->assertEquals($value['total_amount'], $amount, 'Mismatch total amount');
655
656 // Check entity financial trxn created properly
657 $params = [
658 'entity_id' => $contribution['id'],
659 'entity_table' => 'civicrm_contribution',
660 'financial_trxn_id' => $value['id'],
661 ];
662 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
663 $this->assertEquals($eft['values'][$eft['id']]['amount'], $amount);
664 }
665
666 $this->callAPISuccess('Contribution', 'Delete', [
667 'id' => $contribution['id'],
668 ]);
669 }
670
671 /**
672 * Test create payment api for paylater contribution
673 */
674 public function testCreatePaymentPayLater() {
675 $this->createLoggedInUser();
676 $processorID = $this->paymentProcessorCreate();
677 $contributionParams = [
678 'total_amount' => 100,
679 'currency' => 'USD',
680 'contact_id' => $this->_individualId,
681 'financial_type_id' => 1,
682 'contribution_status_id' => 2,
683 'is_pay_later' => 1,
684 ];
685 $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams);
686 //add payment for pay later transaction
687 $params = [
688 'contribution_id' => $contribution['id'],
689 'total_amount' => 100,
690 'card_type_id' => 'Visa',
691 'pan_truncation' => '1234',
692 'trxn_result_code' => 'Startling success',
693 'payment_instrument_id' => $processorID,
694 'trxn_id' => 1234,
695 ];
696 $payment = $this->callAPISuccess('Payment', 'create', $params);
697 $expectedResult = [
698 $payment['id'] => [
699 'from_financial_account_id' => 7,
700 'to_financial_account_id' => 6,
701 'total_amount' => 100,
702 'status_id' => 1,
703 'is_payment' => 1,
704 'card_type_id' => 1,
705 'pan_truncation' => '1234',
706 'trxn_result_code' => 'Startling success',
707 'trxn_id' => 1234,
708 'payment_instrument_id' => 1,
709 ],
710 ];
711 $this->checkPaymentResult($payment, $expectedResult);
712 // Check entity financial trxn created properly
713 $params = [
714 'entity_id' => $contribution['id'],
715 'entity_table' => 'civicrm_contribution',
716 'financial_trxn_id' => $payment['id'],
717 ];
718 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
719 $this->assertEquals($eft['values'][$eft['id']]['amount'], 100);
720 $params = [
721 'entity_table' => 'civicrm_financial_item',
722 'financial_trxn_id' => $payment['id'],
723 ];
724 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
725 $this->assertEquals($eft['values'][$eft['id']]['amount'], 100);
726 // Check contribution for completed status
727 $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id']]);
728 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Completed');
729 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00);
730 $this->callAPISuccess('Contribution', 'Delete', [
731 'id' => $contribution['id'],
732 ]);
733 }
734
735 /**
736 * Test create payment api for pay later contribution with partial payment.
737 *
738 * https://lab.civicrm.org/dev/financial/issues/69
739 */
740 public function testCreatePaymentIncompletePaymentPartialPayment() {
741 $contributionParams = [
742 'total_amount' => 100,
743 'currency' => 'USD',
744 'contact_id' => $this->_individualId,
745 'financial_type_id' => 1,
746 'contribution_status_id' => 2,
747 ];
748 $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams);
749 $this->callAPISuccess('Payment', 'create', [
750 'contribution_id' => $contribution['id'],
751 'total_amount' => 50,
752 'payment_instrument_id' => 'Cash',
753 ]);
754 $payments = $this->callAPISuccess('Payment', 'get', ['contribution_id' => $contribution['id']])['values'];
755 $this->assertCount(1, $payments);
756 }
757
758 /**
759 * Test create payment api for pay later contribution with partial payment.
760 */
761 public function testCreatePaymentPayLaterPartialPayment() {
762 $this->createLoggedInUser();
763 $contributionParams = [
764 'total_amount' => 100,
765 'currency' => 'USD',
766 'contact_id' => $this->_individualId,
767 'financial_type_id' => 1,
768 'contribution_status_id' => 2,
769 'is_pay_later' => 1,
770 ];
771 $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams);
772 //Create partial payment
773 $params = [
774 'contribution_id' => $contribution['id'],
775 'total_amount' => 60,
776 ];
777 $payment = $this->callAPISuccess('Payment', 'create', $params);
778 $expectedResult = [
779 $payment['id'] => [
780 'total_amount' => 60,
781 'status_id' => 1,
782 'is_payment' => 1,
783 ],
784 ];
785 $this->checkPaymentResult($payment, $expectedResult);
786 // Check entity financial trxn created properly
787 $params = [
788 'entity_id' => $contribution['id'],
789 'entity_table' => 'civicrm_contribution',
790 'financial_trxn_id' => $payment['id'],
791 ];
792 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
793 $this->assertEquals($eft['values'][$eft['id']]['amount'], 60);
794 $params = [
795 'entity_table' => 'civicrm_financial_item',
796 'financial_trxn_id' => $payment['id'],
797 ];
798 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
799 $this->assertEquals($eft['values'][$eft['id']]['amount'], 60);
800 $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id']]);
801 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Partially paid');
802 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00);
803 //Create full payment
804 $params = [
805 'contribution_id' => $contribution['id'],
806 'total_amount' => 40,
807 ];
808 // Rename the 'completed' status label first to check that we are not using the labels!
809 $this->callAPISuccess('OptionValue', 'get', ['name' => 'Completed', 'option_group_id' => 'contribution_status', 'api.OptionValue.create' => ['label' => 'Unicorn']]);
810 $payment = $this->callAPISuccess('Payment', 'create', $params);
811 $expectedResult = [
812 $payment['id'] => [
813 'from_financial_account_id' => 7,
814 'to_financial_account_id' => 6,
815 'total_amount' => 40,
816 'status_id' => 1,
817 'is_payment' => 1,
818 ],
819 ];
820 $this->checkPaymentResult($payment, $expectedResult);
821 // Check entity financial trxn created properly
822 $params = [
823 'entity_id' => $contribution['id'],
824 'entity_table' => 'civicrm_contribution',
825 'financial_trxn_id' => $payment['id'],
826 ];
827 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
828 $this->assertEquals($eft['values'][$eft['id']]['amount'], 40);
829 $params = [
830 'entity_table' => 'civicrm_financial_item',
831 'financial_trxn_id' => $payment['id'],
832 ];
833 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
834 $this->assertEquals($eft['values'][$eft['id']]['amount'], 40);
835 // Check contribution for completed status
836 $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id']]);
837 $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Unicorn');
838 $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00);
839 $this->callAPISuccess('Contribution', 'Delete', [
840 'id' => $contribution['id'],
841 ]);
842 $this->callAPISuccess('OptionValue', 'get', ['name' => 'Completed', 'option_group_id' => 'contribution_status', 'api.OptionValue.create' => ['label' => 'Completed']]);
843 $this->callAPISuccessGetCount('Activity', ['target_contact_id' => $this->_individualId, 'activity_type_id' => 'Payment'], 2);
844 }
845
846 /**
847 * Add a location to our event.
848 *
849 * @param int $eventID
850 */
851 protected function addLocationToEvent($eventID) {
852 $addressParams = [
853 'name' => 'event place',
854 'street_address' => 'streety street',
855 'location_type_id' => 1,
856 'is_primary' => 1,
857 ];
858 // api requires contact_id - perhaps incorrectly but use add to get past that.
859 $address = CRM_Core_BAO_Address::add($addressParams);
860
861 $location = $this->callAPISuccess('LocBlock', 'create', ['address_id' => $address->id]);
862 $this->callAPISuccess('Event', 'create', [
863 'id' => $eventID,
864 'loc_block_id' => $location['id'],
865 'is_show_location' => TRUE,
866 ]);
867 }
868
869 }