Merge pull request #15524 from seamuslee001/5_18_3_release_notes
[civicrm-core.git] / tests / phpunit / api / v3 / OrderTest.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_OrderTest extends CiviUnitTestCase {
36
37 protected $_individualId;
38 protected $_financialTypeId = 1;
39 protected $_apiversion;
40 public $debug = 0;
41
42 /**
43 * Setup function.
44 */
45 public function setUp() {
46 parent::setUp();
47
48 $this->_apiversion = 3;
49 $this->_individualId = $this->individualCreate();
50 }
51
52 /**
53 * Clean up after each test.
54 */
55 public function tearDown() {
56 $this->quickCleanUpFinancialEntities();
57 $this->quickCleanup(['civicrm_uf_match']);
58 }
59
60 /**
61 * Test Get order api.
62 */
63 public function testGetOrder() {
64 $contribution = $this->addOrder(FALSE, 100);
65
66 $params = [
67 'contribution_id' => $contribution['id'],
68 ];
69
70 $order = $this->callAPIAndDocument('Order', 'get', $params, __FUNCTION__, __FILE__);
71
72 $this->assertEquals(1, $order['count']);
73 $expectedResult = [
74 $contribution['id'] => [
75 'total_amount' => 100,
76 'contribution_id' => $contribution['id'],
77 'contribution_status' => 'Completed',
78 'net_amount' => 100,
79 ],
80 ];
81 $lineItems[] = [
82 'entity_table' => 'civicrm_contribution',
83 'entity_id' => $contribution['id'],
84 'contribution_id' => $contribution['id'],
85 'unit_price' => 100,
86 'line_total' => 100,
87 'financial_type_id' => 1,
88 ];
89 $this->checkPaymentResult($order, $expectedResult, $lineItems);
90 $this->callAPISuccess('Contribution', 'Delete', [
91 'id' => $contribution['id'],
92 ]);
93 }
94
95 /**
96 * Test Get Order api for participant contribution.
97 */
98 public function testGetOrderParticipant() {
99 $this->addOrder(FALSE, 100);
100 list($items, $contribution) = $this->createParticipantWithContribution();
101
102 $params = [
103 'contribution_id' => $contribution['id'],
104 ];
105
106 $order = $this->callAPISuccess('Order', 'get', $params);
107
108 $this->assertEquals(2, count($order['values'][$contribution['id']]['line_items']));
109 $this->callAPISuccess('Contribution', 'Delete', [
110 'id' => $contribution['id'],
111 ]);
112 }
113
114 /**
115 * Function to assert db values.
116 */
117 public function checkPaymentResult($results, $expectedResult, $lineItems = NULL) {
118 foreach ($expectedResult[$results['id']] as $key => $value) {
119 $this->assertEquals($results['values'][$results['id']][$key], $value);
120 }
121
122 if ($lineItems) {
123 foreach ($lineItems as $key => $items) {
124 foreach ($items as $k => $item) {
125 $this->assertEquals($results['values'][$results['id']]['line_items'][$key][$k], $item);
126 }
127 }
128 }
129 }
130
131 /**
132 * Add order.
133 *
134 * @param bool $isPriceSet
135 * @param float $amount
136 * @param array $extraParams
137 *
138 * @return array
139 */
140 public function addOrder($isPriceSet, $amount = 300.00, $extraParams = []) {
141 $p = [
142 'contact_id' => $this->_individualId,
143 'receive_date' => '2010-01-20',
144 'total_amount' => $amount,
145 'financial_type_id' => $this->_financialTypeId,
146 'contribution_status_id' => 1,
147 ];
148
149 if ($isPriceSet) {
150 $priceFields = $this->createPriceSet();
151 foreach ($priceFields['values'] as $key => $priceField) {
152 $lineItems[1][$key] = [
153 'price_field_id' => $priceField['price_field_id'],
154 'price_field_value_id' => $priceField['id'],
155 'label' => $priceField['label'],
156 'field_title' => $priceField['label'],
157 'qty' => 1,
158 'unit_price' => $priceField['amount'],
159 'line_total' => $priceField['amount'],
160 'financial_type_id' => $priceField['financial_type_id'],
161 ];
162 }
163 $p['line_item'] = $lineItems;
164 }
165 $p = array_merge($extraParams, $p);
166 return $this->callAPISuccess('Contribution', 'create', $p);
167 }
168
169 /**
170 * Test create order api
171 */
172 public function testAddOrder() {
173 $order = $this->addOrder(FALSE, 100);
174 $params = [
175 'contribution_id' => $order['id'],
176 ];
177 $order = $this->callAPISuccess('order', 'get', $params);
178 $expectedResult = [
179 $order['id'] => [
180 'total_amount' => 100,
181 'contribution_id' => $order['id'],
182 'contribution_status' => 'Completed',
183 'net_amount' => 100,
184 ],
185 ];
186 $lineItems[] = [
187 'entity_table' => 'civicrm_contribution',
188 'entity_id' => $order['id'],
189 'contribution_id' => $order['id'],
190 'unit_price' => 100,
191 'line_total' => 100,
192 'financial_type_id' => 1,
193 ];
194 $this->checkPaymentResult($order, $expectedResult, $lineItems);
195 $this->callAPISuccess('Contribution', 'Delete', [
196 'id' => $order['id'],
197 ]);
198 }
199
200 /**
201 * Test create order api for membership
202 */
203 public function testAddOrderForMembership() {
204 $membershipType = $this->membershipTypeCreate();
205 $membershipType1 = $this->membershipTypeCreate();
206 $membershipType = $membershipTypes = [$membershipType, $membershipType1];
207 $p = [
208 'contact_id' => $this->_individualId,
209 'receive_date' => '2010-01-20',
210 'total_amount' => 200,
211 'financial_type_id' => 'Event Fee',
212 'contribution_status_id' => 1,
213 ];
214 $priceFields = $this->createPriceSet();
215 foreach ($priceFields['values'] as $key => $priceField) {
216 $lineItems[$key] = [
217 'price_field_id' => $priceField['price_field_id'],
218 'price_field_value_id' => $priceField['id'],
219 'label' => $priceField['label'],
220 'field_title' => $priceField['label'],
221 'qty' => 1,
222 'unit_price' => $priceField['amount'],
223 'line_total' => $priceField['amount'],
224 'financial_type_id' => $priceField['financial_type_id'],
225 'entity_table' => 'civicrm_membership',
226 'membership_type_id' => array_pop($membershipType),
227 ];
228 }
229 $p['line_items'][] = [
230 'line_item' => [array_pop($lineItems)],
231 'params' => [
232 'contact_id' => $this->_individualId,
233 'membership_type_id' => array_pop($membershipTypes),
234 'join_date' => '2006-01-21',
235 'start_date' => '2006-01-21',
236 'end_date' => '2006-12-21',
237 'source' => 'Payment',
238 'is_override' => 1,
239 'status_id' => 1,
240 ],
241 ];
242 $order = $this->callAPIAndDocument('order', 'create', $p, __FUNCTION__, __FILE__);
243 $params = [
244 'contribution_id' => $order['id'],
245 ];
246 $order = $this->callAPISuccess('order', 'get', $params);
247 $expectedResult = [
248 $order['id'] => [
249 'total_amount' => 200,
250 'contribution_id' => $order['id'],
251 'contribution_status' => 'Completed',
252 'net_amount' => 200,
253 ],
254 ];
255 $this->checkPaymentResult($order, $expectedResult);
256 $this->callAPISuccessGetCount('MembershipPayment', $params, 1);
257 $this->callAPISuccess('Contribution', 'Delete', [
258 'id' => $order['id'],
259 ]);
260 $p['line_items'][] = [
261 'line_item' => [array_pop($lineItems)],
262 'params' => [
263 'contact_id' => $this->_individualId,
264 'membership_type_id' => array_pop($membershipTypes),
265 'join_date' => '2006-01-21',
266 'start_date' => '2006-01-21',
267 'end_date' => '2006-12-21',
268 'source' => 'Payment',
269 'is_override' => 1,
270 'status_id' => 1,
271 ],
272 ];
273 $p['total_amount'] = 300;
274 $order = $this->callAPISuccess('order', 'create', $p);
275 $expectedResult = [
276 $order['id'] => [
277 'total_amount' => 300,
278 'contribution_status' => 'Completed',
279 'net_amount' => 300,
280 ],
281 ];
282 $paymentMembership = [
283 'contribution_id' => $order['id'],
284 ];
285 $order = $this->callAPISuccess('order', 'get', $paymentMembership);
286 $this->checkPaymentResult($order, $expectedResult);
287 $this->callAPISuccessGetCount('MembershipPayment', $paymentMembership, 2);
288 $this->callAPISuccess('Contribution', 'Delete', [
289 'id' => $order['id'],
290 ]);
291 }
292
293 /**
294 * Test create order api for participant
295 */
296 public function testAddOrderForParticipant() {
297 $event = $this->eventCreate();
298 $this->_eventId = $event['id'];
299 $p = [
300 'contact_id' => $this->_individualId,
301 'receive_date' => '2010-01-20',
302 'total_amount' => 300,
303 'financial_type_id' => $this->_financialTypeId,
304 'contribution_status_id' => 1,
305 ];
306 $priceFields = $this->createPriceSet();
307 foreach ($priceFields['values'] as $key => $priceField) {
308 $lineItems[$key] = [
309 'price_field_id' => $priceField['price_field_id'],
310 'price_field_value_id' => $priceField['id'],
311 'label' => $priceField['label'],
312 'field_title' => $priceField['label'],
313 'qty' => 1,
314 'unit_price' => $priceField['amount'],
315 'line_total' => $priceField['amount'],
316 'financial_type_id' => $priceField['financial_type_id'],
317 'entity_table' => 'civicrm_participant',
318 ];
319 }
320 $p['line_items'][] = [
321 'line_item' => $lineItems,
322 'params' => [
323 'contact_id' => $this->_individualId,
324 'event_id' => $this->_eventId,
325 'status_id' => 1,
326 'role_id' => 1,
327 'register_date' => '2007-07-21 00:00:00',
328 'source' => 'Online Event Registration: API Testing',
329 ],
330 ];
331 $order = $this->callAPIAndDocument('order', 'create', $p, __FUNCTION__, __FILE__, 'Create order for participant', 'CreateOrderParticipant');
332 $params = [
333 'contribution_id' => $order['id'],
334 ];
335 $order = $this->callAPISuccess('order', 'get', $params);
336 $expectedResult = [
337 $order['id'] => [
338 'total_amount' => 300,
339 'contribution_id' => $order['id'],
340 'contribution_status' => 'Completed',
341 'net_amount' => 300,
342 ],
343 ];
344 $this->checkPaymentResult($order, $expectedResult);
345 $this->callAPISuccessGetCount('ParticipantPayment', $params, 1);
346 $this->callAPISuccess('Contribution', 'Delete', [
347 'id' => $order['id'],
348 ]);
349 $p['line_items'][] = [
350 'line_item' => $lineItems,
351 'params' => [
352 'contact_id' => $this->individualCreate(),
353 'event_id' => $this->_eventId,
354 'status_id' => 1,
355 'role_id' => 1,
356 'register_date' => '2007-07-21 00:00:00',
357 'source' => 'Online Event Registration: API Testing',
358 ],
359 ];
360 $p['total_amount'] = 600;
361 $order = $this->callAPISuccess('order', 'create', $p);
362 $expectedResult = [
363 $order['id'] => [
364 'total_amount' => 600,
365 'contribution_status' => 'Completed',
366 'net_amount' => 600,
367 ],
368 ];
369 $paymentParticipant = [
370 'contribution_id' => $order['id'],
371 ];
372 $order = $this->callAPISuccess('order', 'get', $paymentParticipant);
373 $this->checkPaymentResult($order, $expectedResult);
374 $this->callAPISuccessGetCount('ParticipantPayment', $paymentParticipant, 2);
375 $this->callAPISuccess('Contribution', 'Delete', [
376 'id' => $order['id'],
377 ]);
378 }
379
380 /**
381 * Test create order api with line items
382 */
383 public function testAddOrderWithLineItems() {
384 $order = $this->addOrder(TRUE);
385 $params = [
386 'contribution_id' => $order['id'],
387 ];
388 $order = $this->callAPISuccess('order', 'get', $params);
389 $expectedResult = [
390 $order['id'] => [
391 'total_amount' => 300,
392 'contribution_id' => $order['id'],
393 'contribution_status' => 'Completed',
394 'net_amount' => 300,
395 ],
396 ];
397 $items[] = [
398 'entity_table' => 'civicrm_contribution',
399 'entity_id' => $order['id'],
400 'contribution_id' => $order['id'],
401 'unit_price' => 100,
402 'line_total' => 100,
403 ];
404 $items[] = [
405 'entity_table' => 'civicrm_contribution',
406 'entity_id' => $order['id'],
407 'contribution_id' => $order['id'],
408 'unit_price' => 200,
409 'line_total' => 200,
410 ];
411 $this->checkPaymentResult($order, $expectedResult, $items);
412 $params = [
413 'entity_table' => 'civicrm_contribution',
414 'entity_id' => $order['id'],
415 ];
416 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
417 $this->assertEquals($eft['values'][$eft['id']]['amount'], 300);
418 $params = [
419 'entity_table' => 'civicrm_financial_item',
420 'financial_trxn_id' => $eft['values'][$eft['id']]['financial_trxn_id'],
421 ];
422 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
423 $amounts = [200, 100];
424 foreach ($eft['values'] as $value) {
425 $this->assertEquals($value['amount'], array_pop($amounts));
426 }
427 $this->callAPISuccess('Contribution', 'Delete', [
428 'id' => $order['id'],
429 ]);
430 }
431
432 /**
433 * Test delete order api
434 */
435 public function testDeleteOrder() {
436 $order = $this->addOrder(FALSE, 100);
437 $params = [
438 'contribution_id' => $order['id'],
439 ];
440 try {
441 $this->callAPISuccess('order', 'delete', $params);
442 $this->fail("Missed expected exception");
443 }
444 catch (Exception $expected) {
445 $this->callAPISuccess('Contribution', 'create', [
446 'contribution_id' => $order['id'],
447 'is_test' => TRUE,
448 ]);
449 $this->callAPIAndDocument('order', 'delete', $params, __FUNCTION__, __FILE__);
450 $order = $this->callAPISuccess('order', 'get', $params);
451 $this->assertEquals(0, $order['count']);
452 }
453 }
454
455 /**
456 * Test cancel order api
457 */
458 public function testCancelOrder() {
459 $contribution = $this->addOrder(FALSE, 100);
460 $params = [
461 'contribution_id' => $contribution['id'],
462 ];
463 $this->callAPIAndDocument('order', 'cancel', $params, __FUNCTION__, __FILE__);
464 $order = $this->callAPISuccess('Order', 'get', $params);
465 $expectedResult = [
466 $contribution['id'] => [
467 'total_amount' => 100,
468 'contribution_id' => $contribution['id'],
469 'contribution_status' => 'Cancelled',
470 'net_amount' => 100,
471 ],
472 ];
473 $this->checkPaymentResult($order, $expectedResult);
474 $this->callAPISuccess('Contribution', 'Delete', [
475 'id' => $contribution['id'],
476 ]);
477 }
478
479 /**
480 * Test cancel order api
481 */
482 public function testCancelWithParticipant() {
483 $event = $this->eventCreate();
484 $this->_eventId = $event['id'];
485 $eventParams = [
486 'id' => $this->_eventId,
487 'financial_type_id' => 4,
488 'is_monetary' => 1,
489 ];
490 $this->callAPISuccess('event', 'create', $eventParams);
491 $participantParams = [
492 'financial_type_id' => 4,
493 'event_id' => $this->_eventId,
494 'role_id' => 1,
495 'status_id' => 1,
496 'fee_currency' => 'USD',
497 'contact_id' => $this->_individualId,
498 ];
499 $participant = $this->callAPISuccess('Participant', 'create', $participantParams);
500 $extraParams = [
501 'contribution_mode' => 'participant',
502 'participant_id' => $participant['id'],
503 ];
504 $contribution = $this->addOrder(TRUE, 100, $extraParams);
505 $paymentParticipant = [
506 'participant_id' => $participant['id'],
507 'contribution_id' => $contribution['id'],
508 ];
509 $this->callAPISuccess('ParticipantPayment', 'create', $paymentParticipant);
510 $params = [
511 'contribution_id' => $contribution['id'],
512 ];
513 $this->callAPISuccess('order', 'cancel', $params);
514 $order = $this->callAPISuccess('Order', 'get', $params);
515 $expectedResult = [
516 $contribution['id'] => [
517 'total_amount' => 100,
518 'contribution_id' => $contribution['id'],
519 'contribution_status' => 'Cancelled',
520 'net_amount' => 100,
521 ],
522 ];
523 $this->checkPaymentResult($order, $expectedResult);
524 $participantPayment = $this->callAPISuccess('ParticipantPayment', 'getsingle', $params);
525 $participant = $this->callAPISuccess('participant', 'get', ['id' => $participantPayment['participant_id']]);
526 $this->assertEquals($participant['values'][$participant['id']]['participant_status'], 'Cancelled');
527 $this->callAPISuccess('Contribution', 'Delete', [
528 'id' => $contribution['id'],
529 ]);
530 }
531
532 /**
533 * @expectedException CiviCRM_API3_Exception
534 * @expectedExceptionMessage Line item total doesn't match with total amount.
535 */
536 public function testCreateOrderIfTotalAmountDoesNotMatchLineItemsAmountsIfNoTaxSupplied() {
537 $params = [
538 'contact_id' => $this->_individualId,
539 'receive_date' => '2018-01-01',
540 'total_amount' => 50,
541 'financial_type_id' => $this->_financialTypeId,
542 'contribution_status_id' => 1,
543 'line_items' => [
544 0 => [
545 'line_item' => [
546 '0' => [
547 'price_field_id' => 1,
548 'price_field_value_id' => 1,
549 'label' => 'Test 1',
550 'field_title' => 'Test 1',
551 'qty' => 1,
552 'unit_price' => 40,
553 'line_total' => 40,
554 'financial_type_id' => 1,
555 'entity_table' => 'civicrm_contribution',
556 ],
557 ],
558 ],
559 ],
560 ];
561
562 civicrm_api3('Order', 'create', $params);
563 }
564
565 /**
566 * @expectedException CiviCRM_API3_Exception
567 * @expectedExceptionMessage Line item total doesn't match with total amount.
568 */
569 public function testCreateOrderIfTotalAmountDoesNotMatchLineItemsAmountsIfTaxSupplied() {
570 $params = [
571 'contact_id' => $this->_individualId,
572 'receive_date' => '2018-01-01',
573 'total_amount' => 50,
574 'financial_type_id' => $this->_financialTypeId,
575 'contribution_status_id' => 1,
576 'tax_amount' => 15,
577 'line_items' => [
578 0 => [
579 'line_item' => [
580 '0' => [
581 'price_field_id' => 1,
582 'price_field_value_id' => 1,
583 'label' => 'Test 1',
584 'field_title' => 'Test 1',
585 'qty' => 1,
586 'unit_price' => 30,
587 'line_total' => 30,
588 'financial_type_id' => 1,
589 'entity_table' => 'civicrm_contribution',
590 'tax_amount' => 15,
591 ],
592 ],
593 ],
594 ],
595 ];
596
597 civicrm_api3('Order', 'create', $params);
598 }
599
600 public function testCreateOrderIfTotalAmountDoesMatchLineItemsAmountsAndTaxSupplied() {
601 $params = [
602 'contact_id' => $this->_individualId,
603 'receive_date' => '2018-01-01',
604 'total_amount' => 50,
605 'financial_type_id' => $this->_financialTypeId,
606 'contribution_status_id' => 1,
607 'tax_amount' => 15,
608 'line_items' => [
609 0 => [
610 'line_item' => [
611 '0' => [
612 'price_field_id' => 1,
613 'price_field_value_id' => 1,
614 'label' => 'Test 1',
615 'field_title' => 'Test 1',
616 'qty' => 1,
617 'unit_price' => 35,
618 'line_total' => 35,
619 'financial_type_id' => 1,
620 'entity_table' => 'civicrm_contribution',
621 'tax_amount' => 15,
622 ],
623 ],
624 ],
625 ],
626 ];
627
628 $order = civicrm_api3('Order', 'create', $params);
629 $this->assertEquals(1, $order['count']);
630 }
631
632 }