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