3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
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 |
9 +--------------------------------------------------------------------+
13 * Test APIv3 civicrm_contribute_* functions
15 * @package CiviCRM_APIv3
16 * @subpackage API_Contribution
19 class api_v3_OrderTest
extends CiviUnitTestCase
{
21 protected $_individualId;
22 protected $_financialTypeId = 1;
28 * @throws \CRM_Core_Exception
30 public function setUp() {
33 $this->_apiversion
= 3;
34 $this->_individualId
= $this->individualCreate();
38 * Clean up after each test.
40 * @throws \CRM_Core_Exception
42 public function tearDown() {
43 $this->quickCleanUpFinancialEntities();
44 $this->quickCleanup(['civicrm_uf_match']);
50 public function testGetOrder() {
51 $contribution = $this->addOrder(FALSE, 100);
54 'contribution_id' => $contribution['id'],
57 $order = $this->callAPIAndDocument('Order', 'get', $params, __FUNCTION__
, __FILE__
);
59 $this->assertEquals(1, $order['count']);
61 $contribution['id'] => [
62 'total_amount' => 100,
63 'contribution_id' => $contribution['id'],
64 'contribution_status' => 'Completed',
69 'entity_table' => 'civicrm_contribution',
70 'entity_id' => $contribution['id'],
71 'contribution_id' => $contribution['id'],
74 'financial_type_id' => 1,
76 $this->checkPaymentResult($order, $expectedResult, $lineItems);
77 $this->callAPISuccess('Contribution', 'Delete', [
78 'id' => $contribution['id'],
83 * Test Get Order api for participant contribution.
85 * @throws \CRM_Core_Exception
87 public function testGetOrderParticipant() {
88 $this->addOrder(FALSE, 100);
89 $contribution = $this->createPartiallyPaidParticipantOrder();
92 'contribution_id' => $contribution['id'],
95 $order = $this->callAPISuccess('Order', 'get', $params);
97 $this->assertCount(2, $order['values'][$contribution['id']]['line_items']);
98 $this->callAPISuccess('Contribution', 'Delete', [
99 'id' => $contribution['id'],
104 * Function to assert db values.
106 public function checkPaymentResult($results, $expectedResult, $lineItems = NULL) {
107 foreach ($expectedResult[$results['id']] as $key => $value) {
108 $this->assertEquals($results['values'][$results['id']][$key], $value);
112 foreach ($lineItems as $key => $items) {
113 foreach ($items as $k => $item) {
114 $this->assertEquals($results['values'][$results['id']]['line_items'][$key][$k], $item);
123 * @param bool $isPriceSet
124 * @param float $amount
125 * @param array $extraParams
129 public function addOrder($isPriceSet, $amount = 300.00, $extraParams = []) {
131 'contact_id' => $this->_individualId
,
132 'receive_date' => '2010-01-20',
133 'total_amount' => $amount,
134 'financial_type_id' => $this->_financialTypeId
,
135 'contribution_status_id' => 1,
139 $priceFields = $this->createPriceSet();
140 foreach ($priceFields['values'] as $key => $priceField) {
141 $lineItems[1][$key] = [
142 'price_field_id' => $priceField['price_field_id'],
143 'price_field_value_id' => $priceField['id'],
144 'label' => $priceField['label'],
145 'field_title' => $priceField['label'],
147 'unit_price' => $priceField['amount'],
148 'line_total' => $priceField['amount'],
149 'financial_type_id' => $priceField['financial_type_id'],
152 $p['line_item'] = $lineItems;
154 $p = array_merge($extraParams, $p);
155 return $this->callAPISuccess('Contribution', 'create', $p);
159 * Test create order api
161 public function testAddOrder() {
162 $order = $this->addOrder(FALSE, 100);
164 'contribution_id' => $order['id'],
166 $order = $this->callAPISuccess('order', 'get', $params);
169 'total_amount' => 100,
170 'contribution_id' => $order['id'],
171 'contribution_status' => 'Completed',
176 'entity_table' => 'civicrm_contribution',
177 'entity_id' => $order['id'],
178 'contribution_id' => $order['id'],
181 'financial_type_id' => 1,
183 $this->checkPaymentResult($order, $expectedResult, $lineItems);
184 $this->callAPISuccess('Contribution', 'Delete', [
185 'id' => $order['id'],
190 * Test create order api for membership
192 * @throws \CRM_Core_Exception
194 public function testAddOrderForMembership() {
195 $membershipType = $this->membershipTypeCreate();
196 $membershipType1 = $this->membershipTypeCreate();
197 $membershipType = $membershipTypes = [$membershipType, $membershipType1];
199 'contact_id' => $this->_individualId
,
200 'receive_date' => '2010-01-20',
201 'financial_type_id' => 'Event Fee',
202 'contribution_status_id' => 'Pending',
204 $priceFields = $this->createPriceSet();
205 foreach ($priceFields['values'] as $key => $priceField) {
207 'price_field_id' => $priceField['price_field_id'],
208 'price_field_value_id' => $priceField['id'],
209 'label' => $priceField['label'],
210 'field_title' => $priceField['label'],
212 'unit_price' => $priceField['amount'],
213 'line_total' => $priceField['amount'],
214 'financial_type_id' => $priceField['financial_type_id'],
215 'entity_table' => 'civicrm_membership',
216 'membership_type_id' => array_pop($membershipType),
219 $p['line_items'][] = [
220 'line_item' => [array_pop($lineItems)],
222 'contact_id' => $this->_individualId
,
223 'membership_type_id' => array_pop($membershipTypes),
224 'join_date' => '2006-01-21',
225 'start_date' => '2006-01-21',
226 'end_date' => '2006-12-21',
227 'source' => 'Payment',
231 $order = $this->callAPIAndDocument('Order', 'create', $p, __FUNCTION__
, __FILE__
);
233 'contribution_id' => $order['id'],
235 $order = $this->callAPISuccess('order', 'get', $params);
238 'total_amount' => 200,
239 'contribution_id' => $order['id'],
240 'contribution_status' => 'Pending Label**',
244 $this->checkPaymentResult($order, $expectedResult);
245 $membershipPayment = $this->callAPISuccessGetSingle('MembershipPayment', $params);
247 $membership = $this->callAPISuccessGetSingle('Membership', ['id' => $membershipPayment['id']]);
248 $this->callAPISuccess('Contribution', 'Delete', [
249 'id' => $order['id'],
251 $p['line_items'][] = [
252 'line_item' => [array_pop($lineItems)],
254 'contact_id' => $this->_individualId
,
255 'membership_type_id' => array_pop($membershipTypes),
256 'join_date' => '2006-01-21',
257 'start_date' => '2006-01-21',
258 'end_date' => '2006-12-21',
259 'source' => 'Payment',
261 'status_id' => 'Pending',
264 $p['total_amount'] = 300;
265 $order = $this->callAPISuccess('order', 'create', $p);
268 'total_amount' => 300,
269 'contribution_status' => 'Pending Label**',
273 $paymentMembership = [
274 'contribution_id' => $order['id'],
276 $order = $this->callAPISuccess('order', 'get', $paymentMembership);
277 $this->checkPaymentResult($order, $expectedResult);
278 $this->callAPISuccessGetCount('MembershipPayment', $paymentMembership, 2);
279 $this->callAPISuccess('Contribution', 'Delete', [
280 'id' => $order['id'],
285 * Test create order api for participant
287 * @throws \CRM_Core_Exception
289 public function testAddOrderForParticipant() {
290 $event = $this->eventCreate();
291 $this->_eventId
= $event['id'];
293 'contact_id' => $this->_individualId
,
294 'receive_date' => '2010-01-20',
295 'financial_type_id' => $this->_financialTypeId
,
296 'contribution_status_id' => 'Pending',
298 $priceFields = $this->createPriceSet();
299 foreach ($priceFields['values'] as $key => $priceField) {
301 'price_field_id' => $priceField['price_field_id'],
302 'price_field_value_id' => $priceField['id'],
303 'label' => $priceField['label'],
304 'field_title' => $priceField['label'],
306 'unit_price' => $priceField['amount'],
307 'line_total' => $priceField['amount'],
308 'financial_type_id' => $priceField['financial_type_id'],
309 'entity_table' => 'civicrm_participant',
312 $p['line_items'][] = [
313 'line_item' => $lineItems,
315 'contact_id' => $this->_individualId
,
316 'event_id' => $this->_eventId
,
318 'register_date' => '2007-07-21 00:00:00',
319 'source' => 'Online Event Registration: API Testing',
323 $order = $this->callAPIAndDocument('order', 'create', $p, __FUNCTION__
, __FILE__
, 'Create order for participant', 'CreateOrderParticipant');
324 $params = ['contribution_id' => $order['id']];
325 $order = $this->callAPISuccess('order', 'get', $params);
328 'total_amount' => 300,
329 'contribution_id' => $order['id'],
330 'contribution_status' => 'Pending Label**',
334 $this->checkPaymentResult($order, $expectedResult);
335 $paymentParticipant = $this->callAPISuccessGetSingle('ParticipantPayment', ['contribution_id' => $order['id']]);
336 $participant = $this->callAPISuccessGetSingle('Participant', ['participant_id' => $paymentParticipant['participant_id']]);
337 $this->assertEquals('Pending (incomplete transaction)', $participant['participant_status']);
338 $this->callAPISuccess('Contribution', 'Delete', [
339 'id' => $order['id'],
342 $p['line_items'][] = [
343 'line_item' => $lineItems,
345 'contact_id' => $this->individualCreate(),
346 'event_id' => $this->_eventId
,
348 'register_date' => '2007-07-21 00:00:00',
349 'source' => 'Online Event Registration: API Testing',
353 $order = $this->callAPISuccess('order', 'create', $p);
356 'total_amount' => 600,
357 'contribution_status' => 'Pending Label**',
361 $paymentParticipant = [
362 'contribution_id' => $order['id'],
364 $order = $this->callAPISuccess('order', 'get', $paymentParticipant);
365 $this->checkPaymentResult($order, $expectedResult);
366 $this->callAPISuccessGetCount('ParticipantPayment', $paymentParticipant, 2);
367 $this->callAPISuccess('Contribution', 'Delete', [
368 'id' => $order['id'],
373 * Test create order api with line items
375 public function testAddOrderWithLineItems() {
376 $order = $this->addOrder(TRUE);
378 'contribution_id' => $order['id'],
380 $order = $this->callAPISuccess('order', 'get', $params);
383 'total_amount' => 300,
384 'contribution_id' => $order['id'],
385 'contribution_status' => 'Completed',
390 'entity_table' => 'civicrm_contribution',
391 'entity_id' => $order['id'],
392 'contribution_id' => $order['id'],
397 'entity_table' => 'civicrm_contribution',
398 'entity_id' => $order['id'],
399 'contribution_id' => $order['id'],
403 $this->checkPaymentResult($order, $expectedResult, $items);
405 'entity_table' => 'civicrm_contribution',
406 'entity_id' => $order['id'],
408 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
409 $this->assertEquals($eft['values'][$eft['id']]['amount'], 300);
411 'entity_table' => 'civicrm_financial_item',
412 'financial_trxn_id' => $eft['values'][$eft['id']]['financial_trxn_id'],
414 $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
415 $amounts = [200, 100];
416 foreach ($eft['values'] as $value) {
417 $this->assertEquals($value['amount'], array_pop($amounts));
419 $this->callAPISuccess('Contribution', 'Delete', [
420 'id' => $order['id'],
425 * Test delete order api
427 public function testDeleteOrder() {
428 $order = $this->addOrder(FALSE, 100);
430 'contribution_id' => $order['id'],
433 $this->callAPISuccess('order', 'delete', $params);
434 $this->fail("Missed expected exception");
436 catch (Exception
$expected) {
437 $this->callAPISuccess('Contribution', 'create', [
438 'contribution_id' => $order['id'],
441 $this->callAPIAndDocument('order', 'delete', $params, __FUNCTION__
, __FILE__
);
442 $order = $this->callAPISuccess('order', 'get', $params);
443 $this->assertEquals(0, $order['count']);
448 * Test cancel order api
450 public function testCancelOrder() {
451 $contribution = $this->addOrder(FALSE, 100);
453 'contribution_id' => $contribution['id'],
455 $this->callAPIAndDocument('order', 'cancel', $params, __FUNCTION__
, __FILE__
);
456 $order = $this->callAPISuccess('Order', 'get', $params);
458 $contribution['id'] => [
459 'total_amount' => 100,
460 'contribution_id' => $contribution['id'],
461 'contribution_status' => 'Cancelled',
465 $this->checkPaymentResult($order, $expectedResult);
466 $this->callAPISuccess('Contribution', 'Delete', [
467 'id' => $contribution['id'],
472 * Test cancel order api
474 public function testCancelWithParticipant() {
475 $event = $this->eventCreate();
476 $this->_eventId
= $event['id'];
478 'id' => $this->_eventId
,
479 'financial_type_id' => 4,
482 $this->callAPISuccess('event', 'create', $eventParams);
483 $participantParams = [
484 'financial_type_id' => 4,
485 'event_id' => $this->_eventId
,
488 'fee_currency' => 'USD',
489 'contact_id' => $this->_individualId
,
491 $participant = $this->callAPISuccess('Participant', 'create', $participantParams);
493 'contribution_mode' => 'participant',
494 'participant_id' => $participant['id'],
496 $contribution = $this->addOrder(TRUE, 100, $extraParams);
497 $paymentParticipant = [
498 'participant_id' => $participant['id'],
499 'contribution_id' => $contribution['id'],
501 $this->callAPISuccess('ParticipantPayment', 'create', $paymentParticipant);
503 'contribution_id' => $contribution['id'],
505 $this->callAPISuccess('order', 'cancel', $params);
506 $order = $this->callAPISuccess('Order', 'get', $params);
508 $contribution['id'] => [
509 'total_amount' => 100,
510 'contribution_id' => $contribution['id'],
511 'contribution_status' => 'Cancelled',
515 $this->checkPaymentResult($order, $expectedResult);
516 $participantPayment = $this->callAPISuccess('ParticipantPayment', 'getsingle', $params);
517 $participant = $this->callAPISuccess('participant', 'get', ['id' => $participantPayment['participant_id']]);
518 $this->assertEquals($participant['values'][$participant['id']]['participant_status'], 'Cancelled');
519 $this->callAPISuccess('Contribution', 'Delete', [
520 'id' => $contribution['id'],
525 * Test an exception is thrown if line items do not add up to total_amount, no tax.
527 public function testCreateOrderIfTotalAmountDoesNotMatchLineItemsAmountsIfNoTaxSupplied() {
529 'contact_id' => $this->_individualId
,
530 'receive_date' => '2018-01-01',
531 'total_amount' => 50,
532 'financial_type_id' => $this->_financialTypeId
,
533 'contribution_status_id' => 'Pending',
538 'price_field_id' => 1,
539 'price_field_value_id' => 1,
541 'field_title' => 'Test 1',
545 'financial_type_id' => 1,
546 'entity_table' => 'civicrm_contribution',
553 $this->callAPIFailure('Order', 'create', $params, 'Line item total doesn\'t match with total amount');
557 * Test an exception is thrown if line items do not add up to total_amount, with tax.
559 public function testCreateOrderIfTotalAmountDoesNotMatchLineItemsAmountsIfTaxSupplied() {
561 'contact_id' => $this->_individualId
,
562 'receive_date' => '2018-01-01',
563 'total_amount' => 50,
564 'financial_type_id' => $this->_financialTypeId
,
565 'contribution_status_id' => 'Pending',
571 'price_field_id' => 1,
572 'price_field_value_id' => 1,
574 'field_title' => 'Test 1',
578 'financial_type_id' => 1,
579 'entity_table' => 'civicrm_contribution',
587 $this->callAPIFailure('Order', 'create', $params, 'Line item total doesn\'t match with total amount.');
590 public function testCreateOrderIfTotalAmountDoesMatchLineItemsAmountsAndTaxSupplied() {
592 'contact_id' => $this->_individualId
,
593 'receive_date' => '2018-01-01',
594 'total_amount' => 50,
595 'financial_type_id' => $this->_financialTypeId
,
596 'contribution_status_id' => 'Pending',
602 'price_field_id' => 1,
603 'price_field_value_id' => 1,
605 'field_title' => 'Test 1',
609 'financial_type_id' => 1,
610 'entity_table' => 'civicrm_contribution',
618 $order = $this->callAPISuccess('Order', 'create', $params);
619 $this->assertEquals(1, $order['count']);
623 * Test that a contribution can be added in pending mode with a chained payment.
625 * We have just deprecated creating an order with a status other than pending. It makes
626 * sense to support adding a payment straight away by chaining.
628 * @throws \CRM_Core_Exception
630 public function testCreateWithChainedPayment() {
631 $contributionID = $this->callAPISuccess('Order', 'create', ['contact_id' => $this->_individualId
, 'total_amount' => 5, 'financial_type_id' => 2, 'contribution_status_id' => 'Pending', 'api.Payment.create' => ['total_amount' => 5]])['id'];
632 $this->assertEquals('Completed', $this->callAPISuccessGetValue('Contribution', ['id' => $contributionID, 'return' => 'contribution_status']));