Metadata fix - phone_type_id, location_type_id, gender_id
[civicrm-core.git] / tests / phpunit / CRM / Contribute / Form / ContributionTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
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 +--------------------------------------------------------------------+
10 */
11
12 /**
13 * Test APIv3 civicrm_contribute_* functions
14 *
15 * @package CiviCRM_APIv3
16 * @subpackage API_Contribution
17 * @group headless
18 */
19 class CRM_Contribute_Form_ContributionTest extends CiviUnitTestCase {
20
21 protected $_individualId;
22 protected $_contribution;
23 protected $_financialTypeId = 1;
24 protected $_entity = 'Contribution';
25 protected $_params;
26 protected $_ids = [];
27 protected $_pageParams = [];
28 protected $_userId;
29
30 /**
31 * Parameters to create payment processor.
32 *
33 * @var array
34 */
35 protected $_processorParams = [];
36
37 /**
38 * ID of created event.
39 *
40 * @var int
41 */
42 protected $_eventID;
43
44 /**
45 * Payment instrument mapping.
46 *
47 * @var array
48 */
49 protected $paymentInstruments = [];
50
51 /**
52 * Products.
53 *
54 * @var array
55 */
56 protected $products = [];
57
58 /**
59 * Dummy payment processor.
60 *
61 * @var CRM_Core_Payment_Dummy
62 */
63 protected $paymentProcessor;
64
65 /**
66 * Payment processor ID.
67 *
68 * @var int
69 */
70 protected $paymentProcessorID;
71
72 /**
73 * Setup function.
74 *
75 * @throws \CRM_Core_Exception
76 * @throws \CiviCRM_API3_Exception
77 */
78 public function setUp() {
79 $this->_apiversion = 3;
80 parent::setUp();
81 $this->_userId = $this->createLoggedInUser();
82
83 $this->_individualId = $this->individualCreate();
84 $this->_params = [
85 'contact_id' => $this->_individualId,
86 'receive_date' => '20120511',
87 'total_amount' => 100.00,
88 'financial_type_id' => $this->_financialTypeId,
89 'non_deductible_amount' => 10.00,
90 'fee_amount' => 5.00,
91 'net_amount' => 95.00,
92 'source' => 'SSF',
93 'contribution_status_id' => 1,
94 ];
95 $this->_processorParams = [
96 'domain_id' => 1,
97 'name' => 'Dummy',
98 'payment_processor_type_id' => 10,
99 'financial_account_id' => 12,
100 'is_active' => 1,
101 'user_name' => '',
102 'url_site' => 'http://dummy.com',
103 'url_recur' => 'http://dummy.com',
104 'billing_mode' => 1,
105 ];
106
107 $instruments = $this->callAPISuccess('contribution', 'getoptions', ['field' => 'payment_instrument_id']);
108 $this->paymentInstruments = $instruments['values'];
109 $product1 = $this->callAPISuccess('product', 'create', [
110 'name' => 'Smurf',
111 'options' => 'brainy smurf, clumsy smurf, papa smurf',
112 ]);
113
114 $this->products[] = $product1['values'][$product1['id']];
115 $this->paymentProcessor = $this->dummyProcessorCreate();
116 $processor = $this->paymentProcessor->getPaymentProcessor();
117 $this->paymentProcessorID = $processor['id'];
118 }
119
120 /**
121 * Clean up after each test.
122 *
123 * @throws \CRM_Core_Exception
124 */
125 public function tearDown() {
126 $this->quickCleanUpFinancialEntities();
127 $this->quickCleanup(['civicrm_note', 'civicrm_uf_match', 'civicrm_address']);
128 }
129
130 /**
131 * CHeck that all tests that have created payments have created them with the right financial entities.
132 *
133 * @throws \CRM_Core_Exception
134 */
135 protected function assertPostConditions() {
136 $this->validateAllPayments();
137 }
138
139 /**
140 * Test the submit function on the contribution page.
141 *
142 * @param string $thousandSeparator
143 *
144 * @dataProvider getThousandSeparators
145 */
146 public function testSubmit($thousandSeparator) {
147 $this->setCurrencySeparators($thousandSeparator);
148 $form = new CRM_Contribute_Form_Contribution();
149 $form->testSubmit([
150 'total_amount' => $this->formatMoneyInput(1234),
151 'financial_type_id' => 1,
152 'contact_id' => $this->_individualId,
153 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
154 'contribution_status_id' => 1,
155 ], CRM_Core_Action::ADD);
156 $contribution = $this->callAPISuccessGetSingle('Contribution', ['contact_id' => $this->_individualId]);
157 $this->assertEmpty($contribution['amount_level']);
158 $this->assertEquals(1234, $contribution['total_amount']);
159 $this->assertEquals(1234, $contribution['net_amount']);
160 }
161
162 /**
163 * Test the submit function on the contribution page.
164 */
165 public function testSubmitCreditCard() {
166 $form = new CRM_Contribute_Form_Contribution();
167 $form->testSubmit([
168 'total_amount' => 50,
169 'financial_type_id' => 1,
170 'contact_id' => $this->_individualId,
171 'payment_instrument_id' => array_search('Credit Card', $this->paymentInstruments),
172 'contribution_status_id' => 1,
173 ], CRM_Core_Action::ADD);
174 $this->callAPISuccessGetCount('Contribution', [
175 'contact_id' => $this->_individualId,
176 'contribution_status_id' => 'Completed',
177 ], 1);
178 }
179
180 /**
181 * Test the submit function on the contribution page.
182 */
183 public function testSubmitCreditCardPayPal() {
184 $mut = new CiviMailUtils($this, TRUE);
185 $mut->clearMessages();
186 $form = new CRM_Contribute_Form_Contribution();
187 $paymentProcessorID = $this->paymentProcessorCreate(['is_test' => 0]);
188 $form->_mode = 'Live';
189 $error = FALSE;
190 try {
191 $form->testSubmit([
192 'total_amount' => 50,
193 'financial_type_id' => 1,
194 'contact_id' => $this->_individualId,
195 'contribution_status_id' => 1,
196 'credit_card_number' => 4444333322221111,
197 'cvv2' => 123,
198 'credit_card_exp_date' => [
199 'M' => 9,
200 'Y' => 2025,
201 ],
202 'credit_card_type' => 'Visa',
203 'billing_first_name' => 'Junko',
204 'billing_middle_name' => '',
205 'billing_last_name' => 'Adams',
206 'billing_street_address-5' => '790L Lincoln St S',
207 'billing_city-5' => 'Maryknoll',
208 'billing_state_province_id-5' => 1031,
209 'billing_postal_code-5' => 10545,
210 'billing_country_id-5' => 1228,
211 'frequency_interval' => 1,
212 'frequency_unit' => 'month',
213 'installments' => '',
214 'hidden_AdditionalDetail' => 1,
215 'hidden_Premium' => 1,
216 'from_email_address' => '"civi45" <civi45@civicrm.com>',
217 'is_email_receipt' => TRUE,
218 'receipt_date' => '',
219 'receipt_date_time' => '',
220 'payment_processor_id' => $paymentProcessorID,
221 'currency' => 'USD',
222 'source' => 'bob sled race',
223 ], CRM_Core_Action::ADD);
224 }
225 catch (Civi\Payment\Exception\PaymentProcessorException $e) {
226 $error = TRUE;
227 }
228
229 $contribution = $this->callAPISuccess('Contribution', 'get', [
230 'contact_id' => $this->_individualId,
231 'contribution_status_id' => $error ? 'Failed' : 'Completed',
232 'payment_instrument_id' => $this->callAPISuccessGetValue('PaymentProcessor', [
233 'return' => 'payment_instrument_id',
234 'id' => $paymentProcessorID,
235 ]),
236 ]);
237
238 $this->assertEquals(1, $contribution["count"], "Contribution count should be one.");
239 $this->assertTrue(!empty($contribution["values"][$contribution["id"]]["receipt_date"]), "Receipt date should not be blank.");
240
241 $contact = $this->callAPISuccessGetSingle('Contact', ['id' => $this->_individualId]);
242 $this->assertTrue(empty($contact['source']));
243 if (!$error) {
244 $msgs = $mut->getAllMessages();
245 $this->assertEquals(1, count($msgs));
246 }
247 $mut->clearMessages();
248 $mut->stop();
249 }
250
251 /**
252 * Test the submit function on the contribution page
253 */
254 public function testSubmitCreditCardWithEmailReceipt() {
255 $mut = new CiviMailUtils($this, TRUE);
256 $mut->clearMessages();
257 $form = new CRM_Contribute_Form_Contribution();
258 $form->_mode = 'Live';
259
260 $form->testSubmit([
261 'total_amount' => 50,
262 'financial_type_id' => 1,
263 'contact_id' => $this->_individualId,
264 'contribution_status_id' => 1,
265 'credit_card_number' => 4444333322221111,
266 'cvv2' => 123,
267 'credit_card_exp_date' => [
268 'M' => 9,
269 'Y' => 2025,
270 ],
271 'credit_card_type' => 'Visa',
272 'billing_first_name' => 'Junko',
273 'billing_middle_name' => '',
274 'billing_last_name' => 'Adams',
275 'billing_street_address-5' => '790L Lincoln St S',
276 'billing_city-5' => 'Maryknoll',
277 'billing_state_province_id-5' => 1031,
278 'billing_postal_code-5' => 10545,
279 'billing_country_id-5' => 1228,
280 'frequency_interval' => 1,
281 'frequency_unit' => 'month',
282 'installments' => '',
283 'hidden_AdditionalDetail' => 1,
284 'hidden_Premium' => 1,
285 'from_email_address' => '"civi45" <civi45@civicrm.com>',
286 'is_email_receipt' => TRUE,
287 'receipt_date' => '',
288 'receipt_date_time' => '',
289 'payment_processor_id' => $this->paymentProcessorID,
290 'currency' => 'USD',
291 'source' => 'bob sled race',
292 ], CRM_Core_Action::ADD);
293
294 $this->callAPISuccessGetCount('Contribution', [
295 'contact_id' => $this->_individualId,
296 'contribution_status_id' => 'Completed',
297 'payment_instrument_id' => $this->callAPISuccessGetValue('PaymentProcessor', [
298 'return' => 'payment_instrument_id',
299 'id' => $this->paymentProcessorID,
300 ]),
301 ], 1);
302 $contact = $this->callAPISuccessGetSingle('Contact', ['id' => $this->_individualId]);
303 $this->assertTrue(empty($contact['source']));
304 $msgs = $mut->getAllMessages();
305 $this->assertEquals(1, count($msgs));
306 $mut->stop();
307 }
308
309 /**
310 * Test the submit function on the contribution page.
311 */
312 public function testSubmitCreditCardNoReceipt() {
313 $mut = new CiviMailUtils($this, TRUE);
314 $mut->clearMessages();
315 $form = new CRM_Contribute_Form_Contribution();
316 $form->_mode = 'Live';
317 $error = FALSE;
318 try {
319 $form->testSubmit([
320 'total_amount' => 60,
321 'financial_type_id' => 1,
322 'contact_id' => $this->_individualId,
323 'contribution_status_id' => 1,
324 'credit_card_number' => 4444333322221111,
325 'cvv2' => 123,
326 'credit_card_exp_date' => [
327 'M' => 9,
328 'Y' => 2025,
329 ],
330 'credit_card_type' => 'Visa',
331 'billing_first_name' => 'Junko',
332 'billing_middle_name' => '',
333 'billing_last_name' => 'Adams',
334 'billing_street_address-5' => '790L Lincoln St S',
335 'billing_city-5' => 'Maryknoll',
336 'billing_state_province_id-5' => 1031,
337 'billing_postal_code-5' => 10545,
338 'billing_country_id-5' => 1228,
339 'frequency_interval' => 1,
340 'frequency_unit' => 'month',
341 'installments' => '',
342 'hidden_AdditionalDetail' => 1,
343 'hidden_Premium' => 1,
344 'from_email_address' => '"civi45" <civi45@civicrm.com>',
345 'is_email_receipt' => FALSE,
346 'receipt_date' => '',
347 'receipt_date_time' => '',
348 'payment_processor_id' => $this->paymentProcessorID,
349 'currency' => 'USD',
350 'source' => 'bob sled race',
351 ], CRM_Core_Action::ADD);
352 }
353 catch (Civi\Payment\Exception\PaymentProcessorException $e) {
354 $error = TRUE;
355 }
356
357 $this->callAPISuccessGetCount('Contribution', [
358 'contact_id' => $this->_individualId,
359 'contribution_status_id' => $error ? 'Failed' : 'Completed',
360 'payment_instrument_id' => $this->callAPISuccessGetValue('PaymentProcessor', [
361 'return' => 'payment_instrument_id',
362 'id' => $this->paymentProcessorID,
363 ]),
364 ], 1);
365 $contact = $this->callAPISuccessGetSingle('Contact', ['id' => $this->_individualId]);
366 $this->assertTrue(empty($contact['source']));
367 $mut->assertMailLogEmpty();
368 $mut->stop();
369 }
370
371 /**
372 * Test the submit function on the contribution page.
373 */
374 public function testSubmitCreditCardFee() {
375 $form = new CRM_Contribute_Form_Contribution();
376 $this->paymentProcessor->setDoDirectPaymentResult(['is_error' => 0, 'trxn_id' => 'tx', 'fee_amount' => .08]);
377 $form->_mode = 'Live';
378 $form->testSubmit([
379 'total_amount' => 50,
380 'financial_type_id' => 1,
381 'contact_id' => $this->_individualId,
382 'payment_instrument_id' => array_search('Credit Card', $this->paymentInstruments),
383 'contribution_status_id' => 1,
384 'credit_card_number' => 4444333322221111,
385 'cvv2' => 123,
386 'credit_card_exp_date' => [
387 'M' => 9,
388 'Y' => 2025,
389 ],
390 'credit_card_type' => 'Visa',
391 'billing_first_name' => 'Junko',
392 'billing_middle_name' => '',
393 'billing_last_name' => 'Adams',
394 'billing_street_address-5' => '790L Lincoln St S',
395 'billing_city-5' => 'Maryknoll',
396 'billing_state_province_id-5' => 1031,
397 'billing_postal_code-5' => 10545,
398 'billing_country_id-5' => 1228,
399 'frequency_interval' => 1,
400 'frequency_unit' => 'month',
401 'installments' => '',
402 'hidden_AdditionalDetail' => 1,
403 'hidden_Premium' => 1,
404 'from_email_address' => '"civi45" <civi45@civicrm.com>',
405 'receipt_date' => '',
406 'receipt_date_time' => '',
407 'payment_processor_id' => $this->paymentProcessorID,
408 'currency' => 'USD',
409 'source' => '',
410 ], CRM_Core_Action::ADD);
411
412 $contribution = $this->callAPISuccessGetSingle('Contribution', [
413 'contact_id' => $this->_individualId,
414 'contribution_status_id' => 'Completed',
415 ]);
416 $this->assertEquals('50.00', $contribution['total_amount']);
417 $this->assertEquals(.08, $contribution['fee_amount']);
418 $this->assertEquals(49.92, $contribution['net_amount']);
419 $this->assertEquals('tx', $contribution['trxn_id']);
420 $this->assertEmpty($contribution['amount_level']);
421 }
422
423 /**
424 * Test a fully deductible contribution submitted by credit card (CRM-16669).
425 */
426 public function testSubmitCreditCardFullyDeductible() {
427 $form = new CRM_Contribute_Form_Contribution();
428 $form->_mode = 'Live';
429 $form->testSubmit([
430 'total_amount' => 50,
431 'financial_type_id' => 1,
432 'contact_id' => $this->_individualId,
433 'payment_instrument_id' => array_search('Credit Card', $this->paymentInstruments),
434 'contribution_status_id' => 1,
435 'credit_card_number' => 4444333322221111,
436 'cvv2' => 123,
437 'credit_card_exp_date' => [
438 'M' => 9,
439 'Y' => 2025,
440 ],
441 'credit_card_type' => 'Visa',
442 'billing_first_name' => 'Junko',
443 'billing_middle_name' => '',
444 'billing_last_name' => 'Adams',
445 'billing_street_address-5' => '790L Lincoln St S',
446 'billing_city-5' => 'Maryknoll',
447 'billing_state_province_id-5' => 1031,
448 'billing_postal_code-5' => 10545,
449 'billing_country_id-5' => 1228,
450 'frequency_interval' => 1,
451 'frequency_unit' => 'month',
452 'installments' => '',
453 'hidden_AdditionalDetail' => 1,
454 'hidden_Premium' => 1,
455 'from_email_address' => '"civi45" <civi45@civicrm.com>',
456 'receipt_date' => '',
457 'receipt_date_time' => '',
458 'payment_processor_id' => $this->paymentProcessorID,
459 'currency' => 'USD',
460 'source' => '',
461 ], CRM_Core_Action::ADD);
462
463 $contribution = $this->callAPISuccessGetSingle('Contribution', [
464 'contact_id' => $this->_individualId,
465 'contribution_status_id' => 'Completed',
466 ]);
467 $this->assertEquals('50.00', $contribution['total_amount']);
468 $this->assertEquals(0, $contribution['non_deductible_amount']);
469 }
470
471 /**
472 * Test the submit function with an invalid payment.
473 *
474 * We expect the contribution to be created but left pending. The payment has failed.
475 *
476 * Test covers CRM-16417 change to keep failed transactions.
477 *
478 * We are left with
479 * - 1 Contribution with status = Pending
480 * - 1 Line item
481 * - 1 civicrm_financial_item. This is linked to the line item and has a status of 3
482 *
483 * @throws \CRM_Core_Exception
484 * @throws \CiviCRM_API3_Exception
485 */
486 public function testSubmitCreditCardInvalid() {
487 $form = new CRM_Contribute_Form_Contribution();
488 $this->paymentProcessor->setDoDirectPaymentResult(['is_error' => 1]);
489 try {
490 $form->testSubmit([
491 'total_amount' => 50,
492 'financial_type_id' => 1,
493 'contact_id' => $this->_individualId,
494 'payment_instrument_id' => array_search('Credit Card', $this->paymentInstruments),
495 'payment_processor_id' => $this->paymentProcessorID,
496 'credit_card_exp_date' => ['M' => 5, 'Y' => 2012],
497 'credit_card_number' => '411111111111111',
498 ], CRM_Core_Action::ADD, 'live');
499 }
500 catch (\Civi\Payment\Exception\PaymentProcessorException $e) {
501 $this->callAPISuccessGetCount('Contribution', [
502 'contact_id' => $this->_individualId,
503 'contribution_status_id' => 'Failed',
504 ], 1);
505 $lineItem = $this->callAPISuccessGetSingle('line_item', []);
506 $this->assertEquals('50.00', $lineItem['unit_price']);
507 $this->assertEquals('50.00', $lineItem['line_total']);
508 $this->assertEquals(1, $lineItem['qty']);
509 $this->assertEquals(1, $lineItem['financial_type_id']);
510 $financialItem = $this->callAPISuccessGetSingle('financial_item', [
511 'civicrm_line_item' => $lineItem['id'],
512 'entity_id' => $lineItem['id'],
513 ]);
514 $this->assertEquals('50.00', $financialItem['amount']);
515 $this->assertEquals(3, $financialItem['status_id']);
516 return;
517 }
518 $this->fail('An expected exception has not been raised.');
519 }
520
521 /**
522 * Test the submit function creates a billing address if provided.
523 *
524 * @throws \CRM_Core_Exception
525 * @throws \CiviCRM_API3_Exception
526 */
527 public function testSubmitCreditCardWithBillingAddress() {
528 $form = new CRM_Contribute_Form_Contribution();
529 $form->testSubmit([
530 'total_amount' => 50,
531 'financial_type_id' => 1,
532 'contact_id' => $this->_individualId,
533 'payment_instrument_id' => array_search('Credit Card', $this->paymentInstruments),
534 'payment_processor_id' => $this->paymentProcessorID,
535 'credit_card_exp_date' => ['M' => 5, 'Y' => 2025],
536 'credit_card_number' => '411111111111111',
537 'billing_city-5' => 'Vancouver',
538 ], CRM_Core_Action::ADD, 'live');
539 $contribution = $this->callAPISuccessGetSingle('Contribution', ['return' => 'address_id']);
540 $this->assertNotEmpty($contribution['address_id']);
541 // CRM-18490 : There is a unwanted test leakage due to below getsingle Api as it only fails in Jenkin
542 // for now we are only fetching address on based on Address ID (removed filter location_type_id and city)
543 $this->callAPISuccessGetSingle('Address', [
544 'id' => $contribution['address_id'],
545 ]);
546 }
547
548 /**
549 * CRM-20745: Test the submit function correctly sets the
550 * receive date for recurring contribution.
551 */
552 public function testSubmitCreditCardWithRecur() {
553 $form = new CRM_Contribute_Form_Contribution();
554 $receiveDate = date('Y-m-d H:i:s', strtotime('+1 month'));
555 $form->testSubmit([
556 'total_amount' => 50,
557 'financial_type_id' => 1,
558 'is_recur' => 1,
559 'frequency_interval' => 2,
560 'frequency_unit' => 'month',
561 'installments' => 2,
562 'receive_date' => $receiveDate,
563 'contact_id' => $this->_individualId,
564 'payment_instrument_id' => array_search('Credit Card', $this->paymentInstruments),
565 'payment_processor_id' => $this->paymentProcessorID,
566 'credit_card_exp_date' => ['M' => 5, 'Y' => 2025],
567 'credit_card_number' => '411111111111111',
568 'billing_city-5' => 'Vancouver',
569 ], CRM_Core_Action::ADD, 'live');
570 $contribution = $this->callAPISuccessGetSingle('Contribution', ['return' => 'receive_date']);
571 $this->assertEquals($contribution['receive_date'], $receiveDate);
572 }
573
574 /**
575 * Test the submit function does not create a billing address if no details provided.
576 */
577 public function testSubmitCreditCardWithNoBillingAddress() {
578 $form = new CRM_Contribute_Form_Contribution();
579 $form->testSubmit([
580 'total_amount' => 50,
581 'financial_type_id' => 1,
582 'contact_id' => $this->_individualId,
583 'payment_instrument_id' => array_search('Credit Card', $this->paymentInstruments),
584 'payment_processor_id' => $this->paymentProcessorID,
585 'credit_card_exp_date' => ['M' => 5, 'Y' => 2025],
586 'credit_card_number' => '411111111111111',
587 ], CRM_Core_Action::ADD, 'live');
588 $contribution = $this->callAPISuccessGetSingle('Contribution', ['return' => 'address_id']);
589 $this->assertEmpty($contribution['address_id']);
590 $this->callAPISuccessGetCount('Address', [
591 'city' => 'Vancouver',
592 'location_type_id' => 5,
593 ], 0);
594 }
595
596 /**
597 * Test the submit function on the contribution page.
598 *
599 * @throws \CRM_Core_Exception
600 * @throws \CiviCRM_API3_Exception
601 */
602 public function testSubmitEmailReceipt() {
603 $form = new CRM_Contribute_Form_Contribution();
604 $mut = new CiviMailUtils($this, TRUE);
605 $form->testSubmit([
606 'total_amount' => 50,
607 'financial_type_id' => 1,
608 'contact_id' => $this->_individualId,
609 'is_email_receipt' => TRUE,
610 'from_email_address' => 'test@test.com',
611 'contribution_status_id' => 1,
612 ], CRM_Core_Action::ADD);
613 $this->callAPISuccessGetCount('Contribution', ['contact_id' => $this->_individualId], 1);
614 $mut->checkMailLog([
615 'Contribution Information',
616 ]);
617 $mut->stop();
618 }
619
620 /**
621 * Test the submit function on the contribution page using numerical from email address.
622 */
623 public function testSubmitEmailReceiptUserEmailFromAddress() {
624 $form = new CRM_Contribute_Form_Contribution();
625 $mut = new CiviMailUtils($this, TRUE);
626 $email = $this->callAPISuccess('Email', 'create', [
627 'contact_id' => $this->_userId,
628 'email' => 'testLoggedIn@example.com',
629 ]);
630 $form->testSubmit([
631 'total_amount' => 50,
632 'financial_type_id' => 1,
633 'contact_id' => $this->_individualId,
634 'is_email_receipt' => TRUE,
635 'from_email_address' => $email['id'],
636 'contribution_status_id' => 1,
637 ], CRM_Core_Action::ADD);
638 $this->callAPISuccessGetCount('Contribution', ['contact_id' => $this->_individualId], 1);
639 $mut->checkMailLog([
640 'Below you will find a receipt for this contribution.',
641 '<testloggedin@example.com>',
642 ]);
643 $mut->stop();
644 }
645
646 /**
647 * Ensure that price field are shown during pay later/pending Contribution
648 */
649 public function testEmailReceiptOnPayLater() {
650 $donationFT = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', 'Donation', 'id', 'name');
651 $paramsSet = [
652 'title' => 'Price Set' . substr(sha1(rand()), 0, 4),
653 'is_active' => TRUE,
654 'financial_type_id' => $donationFT,
655 'extends' => 2,
656 ];
657 $paramsSet['name'] = CRM_Utils_String::titleToVar($paramsSet['title']);
658
659 $priceset = CRM_Price_BAO_PriceSet::create($paramsSet);
660 $priceSetId = $priceset->id;
661
662 //Checking for priceset added in the table.
663 $this->assertDBCompareValue('CRM_Price_BAO_PriceSet', $priceSetId, 'title',
664 'id', $paramsSet['title'], 'Check DB for created priceset'
665 );
666 $paramsField = [
667 'label' => 'Price Field',
668 'name' => CRM_Utils_String::titleToVar('Price Field'),
669 'html_type' => 'CheckBox',
670 'option_label' => ['1' => 'Price Field 1', '2' => 'Price Field 2'],
671 'option_value' => ['1' => 100, '2' => 200],
672 'option_name' => ['1' => 'Price Field 1', '2' => 'Price Field 2'],
673 'option_weight' => ['1' => 1, '2' => 2],
674 'option_amount' => ['1' => 100, '2' => 200],
675 'is_display_amounts' => 1,
676 'weight' => 1,
677 'options_per_line' => 1,
678 'is_active' => ['1' => 1, '2' => 1],
679 'price_set_id' => $priceset->id,
680 'is_enter_qty' => 1,
681 'financial_type_id' => $donationFT,
682 ];
683 $priceField = CRM_Price_BAO_PriceField::create($paramsField);
684 $priceFieldValue = $this->callAPISuccess('PriceFieldValue', 'get', ['price_field_id' => $priceField->id]);
685
686 $params = [
687 'total_amount' => 100,
688 'financial_type_id' => $donationFT,
689 'contact_id' => $this->_individualId,
690 'is_email_receipt' => TRUE,
691 'from_email_address' => 'test@test.com',
692 'price_set_id' => $priceSetId,
693 'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending'),
694 ];
695
696 foreach ($priceFieldValue['values'] as $id => $price) {
697 if ($price['amount'] == 100) {
698 $params['price_' . $priceField->id] = [$id => 1];
699 }
700 }
701 $form = new CRM_Contribute_Form_Contribution();
702 $mut = new CiviMailUtils($this, TRUE);
703 $form->_priceSet = current(CRM_Price_BAO_PriceSet::getSetDetail($priceSetId));
704 $form->testSubmit($params, CRM_Core_Action::ADD);
705
706 $mut->checkMailLog([
707 'Financial Type: Donation
708 ---------------------------------------------------------
709 Item Qty Each Total
710 ----------------------------------------------------------
711 Price Field - Price Field 1 1 $ 100.00 $ 100.00
712 ',
713 ]);
714 $mut->stop();
715 }
716
717 /**
718 * Test that a contribution is assigned against a pledge.
719 */
720 public function testUpdatePledge() {
721 $pledge = $this->callAPISuccess('pledge', 'create', [
722 'contact_id' => $this->_individualId,
723 'pledge_create_date' => date('Ymd'),
724 'start_date' => date('Ymd'),
725 'amount' => 100.00,
726 'pledge_status_id' => '2',
727 'pledge_financial_type_id' => '1',
728 'pledge_original_installment_amount' => 20,
729 'frequency_interval' => 5,
730 'frequency_unit' => 'year',
731 'frequency_day' => 15,
732 'installments' => 2,
733 'sequential' => 1,
734 ]);
735 $pledgePaymentID = $this->callAPISuccess('pledge_payment', 'getvalue', [
736 'pledge_id' => $pledge['id'],
737 'options' => ['limit' => 1],
738 'return' => 'id',
739 ]);
740 $form = new CRM_Contribute_Form_Contribution();
741 $form->testSubmit([
742 'total_amount' => 50,
743 'financial_type_id' => 1,
744 'contact_id' => $this->_individualId,
745 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
746 'pledge_payment_id' => $pledgePaymentID,
747 'contribution_status_id' => 1,
748 ], CRM_Core_Action::ADD);
749 $pledgePayment = $this->callAPISuccess('pledge_payment', 'getsingle', ['id' => $pledgePaymentID]);
750 $this->assertNotEmpty($pledgePayment['contribution_id']);
751 $this->assertEquals($pledgePayment['actual_amount'], 50);
752 $this->assertEquals(1, $pledgePayment['status_id']);
753 }
754
755 /**
756 * Test functions involving premiums.
757 */
758 public function testPremiumUpdate() {
759 $form = new CRM_Contribute_Form_Contribution();
760 $mut = new CiviMailUtils($this, TRUE);
761 $form->testSubmit([
762 'total_amount' => 50,
763 'financial_type_id' => 1,
764 'contact_id' => $this->_individualId,
765 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
766 'contribution_status_id' => 1,
767 'product_name' => [$this->products[0]['id'], 1],
768 'fulfilled_date' => '',
769 'is_email_receipt' => TRUE,
770 'from_email_address' => 'test@test.com',
771 ], CRM_Core_Action::ADD);
772 $contributionProduct = $this->callAPISuccess('contribution_product', 'getsingle', []);
773 $this->assertEquals('clumsy smurf', $contributionProduct['product_option']);
774 $mut->checkMailLog([
775 'Premium Information',
776 'Smurf',
777 'clumsy smurf',
778 ]);
779 $mut->stop();
780 }
781
782 /**
783 * Test functions involving premiums.
784 */
785 public function testPremiumUpdateCreditCard() {
786 $form = new CRM_Contribute_Form_Contribution();
787 $mut = new CiviMailUtils($this, TRUE);
788 $form->testSubmit([
789 'total_amount' => 50,
790 'financial_type_id' => 1,
791 'contact_id' => $this->_individualId,
792 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
793 'contribution_status_id' => 1,
794 'product_name' => [$this->products[0]['id'], 1],
795 'fulfilled_date' => '',
796 'is_email_receipt' => TRUE,
797 'from_email_address' => 'test@test.com',
798 'payment_processor_id' => $this->paymentProcessorID,
799 'credit_card_exp_date' => ['M' => 5, 'Y' => 2026],
800 'credit_card_number' => '411111111111111',
801 ], CRM_Core_Action::ADD, 'live');
802 $contributionProduct = $this->callAPISuccess('contribution_product', 'getsingle', []);
803 $this->assertEquals('clumsy smurf', $contributionProduct['product_option']);
804 $mut->checkMailLog([
805 'Premium Information',
806 'Smurf',
807 'clumsy smurf',
808 ]);
809 $mut->stop();
810 }
811
812 /**
813 * Test the submit function on the contribution page.
814 */
815 public function testSubmitWithNote() {
816 $form = new CRM_Contribute_Form_Contribution();
817 $form->testSubmit([
818 'total_amount' => 50,
819 'financial_type_id' => 1,
820 'contact_id' => $this->_individualId,
821 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
822 'contribution_status_id' => 1,
823 'note' => 'Super cool and interesting stuff',
824 ], CRM_Core_Action::ADD);
825 $this->callAPISuccessGetCount('Contribution', ['contact_id' => $this->_individualId], 1);
826 $note = $this->callAPISuccessGetSingle('note', ['entity_table' => 'civicrm_contribution']);
827 $this->assertEquals($note['note'], 'Super cool and interesting stuff');
828 }
829
830 /**
831 * Test the submit function on the contribution page.
832 */
833 public function testSubmitWithNoteCreditCard() {
834 $form = new CRM_Contribute_Form_Contribution();
835
836 $form->testSubmit([
837 'total_amount' => 50,
838 'financial_type_id' => 1,
839 'contact_id' => $this->_individualId,
840 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
841 'contribution_status_id' => 1,
842 'note' => 'Super cool and interesting stuff',
843 ] + $this->getCreditCardParams(),
844 CRM_Core_Action::ADD);
845 $this->callAPISuccessGetCount('Contribution', ['contact_id' => $this->_individualId], 1);
846 $note = $this->callAPISuccessGetSingle('note', ['entity_table' => 'civicrm_contribution']);
847 $this->assertEquals($note['note'], 'Super cool and interesting stuff');
848 }
849
850 /**
851 * Test that if a negative contribution is entered it does not get reset to $0.
852 *
853 * Note that this fails locally for me & I believe there may be an issue for some sites
854 * with negative numbers. Grep for CRM-16460 to find the places I think that might
855 * be affected if you hit this.
856 */
857 public function testEnterNegativeContribution() {
858 $form = new CRM_Contribute_Form_Contribution();
859 $form->testSubmit([
860 'total_amount' => -5,
861 'financial_type_id' => 1,
862 'contact_id' => $this->_individualId,
863 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
864 'contribution_status_id' => 1,
865 ],
866 CRM_Core_Action::ADD);
867 $this->callAPISuccessGetCount('Contribution', ['contact_id' => $this->_individualId], 1);
868
869 $contribution = $this->callAPISuccessGetSingle('Contribution', [
870 'contact_id' => $this->_individualId,
871 ]);
872 $this->assertEquals(-5, $contribution['total_amount']);
873 }
874
875 /**
876 * Test the submit function on the contribution page.
877 *
878 * @param string $thousandSeparator
879 *
880 * @dataProvider getThousandSeparators
881 */
882 public function testSubmitUpdate($thousandSeparator) {
883 $this->setCurrencySeparators($thousandSeparator);
884 $form = new CRM_Contribute_Form_Contribution();
885
886 $form->testSubmit([
887 'total_amount' => $this->formatMoneyInput(6100.10),
888 'financial_type_id' => 1,
889 'contact_id' => $this->_individualId,
890 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
891 'contribution_status_id' => 1,
892 'price_set_id' => 0,
893 ], CRM_Core_Action::ADD);
894 $contribution = $this->callAPISuccessGetSingle('Contribution', ['contact_id' => $this->_individualId]);
895 $form->testSubmit([
896 'total_amount' => $this->formatMoneyInput(5200.20),
897 'net_amount' => $this->formatMoneyInput(5200.20),
898 'financial_type_id' => 1,
899 'contact_id' => $this->_individualId,
900 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
901 'contribution_status_id' => 1,
902 'price_set_id' => 0,
903 'id' => $contribution['id'],
904 ], CRM_Core_Action::UPDATE);
905 $contribution = $this->callAPISuccessGetSingle('Contribution', ['contact_id' => $this->_individualId]);
906 $this->assertEquals(5200.20, $contribution['total_amount'], 2);
907
908 $financialTransactions = $this->callAPISuccess('FinancialTrxn', 'get', ['sequential' => TRUE]);
909 $this->assertEquals(2, $financialTransactions['count']);
910 $this->assertEquals(6100.10, $financialTransactions['values'][0]['total_amount']);
911 $this->assertEquals(-899.90, $financialTransactions['values'][1]['total_amount']);
912 $this->assertEquals(-899.90, $financialTransactions['values'][1]['net_amount']);
913 $lineItem = $this->callAPISuccessGetSingle('LineItem', []);
914 $this->assertEquals(5200.20, $lineItem['line_total']);
915 }
916
917 /**
918 * Test the submit function if only payment instrument is changed from 'Check' to 'Credit Card'
919 *
920 * @param string $thousandSeparator
921 *
922 * @dataProvider getThousandSeparators
923 */
924 public function testSubmitUpdateChangePaymentInstrument($thousandSeparator) {
925 $this->setCurrencySeparators($thousandSeparator);
926 $form = new CRM_Contribute_Form_Contribution();
927
928 $form->testSubmit([
929 'total_amount' => 1200.55,
930 'financial_type_id' => 1,
931 'contact_id' => $this->_individualId,
932 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
933 'check_number' => '123AX',
934 'contribution_status_id' => 1,
935 'price_set_id' => 0,
936 ], CRM_Core_Action::ADD);
937 $contribution = $this->callAPISuccessGetSingle('Contribution', ['contact_id' => $this->_individualId]);
938 $form->testSubmit([
939 'total_amount' => 1200.55,
940 'net_amount' => 1200.55,
941 'financial_type_id' => 1,
942 'contact_id' => $this->_individualId,
943 'payment_instrument_id' => array_search('Credit Card', $this->paymentInstruments),
944 'card_type_id' => CRM_Core_PseudoConstant::getKey('CRM_Financial_DAO_FinancialTrxn', 'card_type_id', 'Visa'),
945 'pan_truncation' => '1011',
946 'contribution_status_id' => 1,
947 'price_set_id' => 0,
948 'id' => $contribution['id'],
949 ], CRM_Core_Action::UPDATE);
950 $contribution = $this->callAPISuccessGetSingle('Contribution', ['contact_id' => $this->_individualId]);
951 $this->assertEquals(1200.55, $contribution['total_amount']);
952
953 $financialTransactions = $this->callAPISuccess('FinancialTrxn', 'get', ['sequential' => TRUE]);
954 $this->assertEquals(3, $financialTransactions['count']);
955
956 list($oldTrxn, $reversedTrxn, $latestTrxn) = $financialTransactions['values'];
957
958 $this->assertEquals(1200.55, $oldTrxn['total_amount']);
959 $this->assertEquals('123AX', $oldTrxn['check_number']);
960 $this->assertEquals(array_search('Check', $this->paymentInstruments), $oldTrxn['payment_instrument_id']);
961
962 $this->assertEquals(-1200.55, $reversedTrxn['total_amount']);
963 $this->assertEquals('123AX', $reversedTrxn['check_number']);
964 $this->assertEquals(array_search('Check', $this->paymentInstruments), $reversedTrxn['payment_instrument_id']);
965
966 $this->assertEquals(1200.55, $latestTrxn['total_amount']);
967 $this->assertEquals('1011', $latestTrxn['pan_truncation']);
968 $this->assertEquals(array_search('Credit Card', $this->paymentInstruments), $latestTrxn['payment_instrument_id']);
969 $lineItem = $this->callAPISuccessGetSingle('LineItem', []);
970 }
971
972 /**
973 * Get parameters for credit card submit calls.
974 *
975 * @return array
976 * Credit card specific parameters.
977 */
978 protected function getCreditCardParams() {
979 return [
980 'payment_processor_id' => $this->paymentProcessorID,
981 'credit_card_exp_date' => ['M' => 5, 'Y' => 2012],
982 'credit_card_number' => '411111111111111',
983 ];
984 }
985
986 /**
987 * Test the submit function that completes the partially paid payment using Credit Card
988 *
989 * @throws \CRM_Core_Exception
990 * @throws \CiviCRM_API3_Exception
991 */
992 public function testPartialPaymentWithCreditCard() {
993 // create a partially paid contribution by using back-office form
994 $form = new CRM_Contribute_Form_Contribution();
995 $form->testSubmit(
996 [
997 'total_amount' => 50,
998 'financial_type_id' => 1,
999 'contact_id' => $this->_individualId,
1000 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
1001 'check_number' => substr(sha1(rand()), 0, 7),
1002 'billing_city-5' => 'Vancouver',
1003 'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending'),
1004 ], CRM_Core_Action::ADD
1005 );
1006
1007 $contribution = $this->callAPISuccessGetSingle('Contribution', []);
1008 $this->callAPISuccess('Payment', 'create', ['contribution_id' => $contribution['id'], 'total_amount' => 10, 'payment_instrument_id' => 'Cash']);
1009 $contribution = $this->callAPISuccessGetSingle('Contribution', ['id' => $contribution['id']]);
1010 $this->assertEquals('Partially paid', $contribution['contribution_status']);
1011 // pay additional amount by using Credit Card
1012 $form = new CRM_Contribute_Form_AdditionalPayment();
1013 $form->testSubmit([
1014 'contribution_id' => $contribution['id'],
1015 'contact_id' => $this->_individualId,
1016 'total_amount' => 40,
1017 'currency' => 'USD',
1018 'financial_type_id' => 1,
1019 'payment_instrument_id' => array_search('Credit Card', $this->paymentInstruments),
1020 'payment_processor_id' => $this->paymentProcessorID,
1021 'credit_card_exp_date' => ['M' => 5, 'Y' => 2025],
1022 'credit_card_number' => '411111111111111',
1023 'cvv2' => 234,
1024 'credit_card_type' => 'Visa',
1025 'billing_city-5' => 'Vancouver',
1026 'billing_state_province_id-5' => 1059,
1027 'billing_postal_code-5' => 1321312,
1028 'billing_country_id-5' => 1228,
1029 'trxn_date' => '2017-04-11 13:05:11',
1030 ], 'live');
1031 $contribution = $this->callAPISuccessGetSingle('Contribution', []);
1032 $this->assertNotEmpty($contribution);
1033 $this->assertEquals('Completed', $contribution['contribution_status']);
1034 }
1035
1036 /**
1037 * Test the submit function for FT with tax.
1038 *
1039 * @param string $thousandSeparator
1040 *
1041 * @dataProvider getThousandSeparators
1042 */
1043 public function testSubmitSaleTax($thousandSeparator) {
1044 $this->setCurrencySeparators($thousandSeparator);
1045 $this->enableTaxAndInvoicing();
1046 $this->relationForFinancialTypeWithFinancialAccount($this->_financialTypeId);
1047 $form = new CRM_Contribute_Form_Contribution();
1048
1049 $form->testSubmit([
1050 'total_amount' => $this->formatMoneyInput(1000.00),
1051 'financial_type_id' => $this->_financialTypeId,
1052 'contact_id' => $this->_individualId,
1053 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
1054 'contribution_status_id' => 1,
1055 'price_set_id' => 0,
1056 ],
1057 CRM_Core_Action::ADD
1058 );
1059 $contribution = $this->callAPISuccessGetSingle('Contribution',
1060 [
1061 'contact_id' => $this->_individualId,
1062 'return' => ['tax_amount', 'total_amount'],
1063 ]
1064 );
1065 $this->assertEquals(1100, $contribution['total_amount']);
1066 $this->assertEquals(100, $contribution['tax_amount']);
1067 $this->callAPISuccessGetCount('FinancialTrxn', [], 1);
1068 $this->callAPISuccessGetCount('FinancialItem', [], 2);
1069 $lineItem = $this->callAPISuccessGetSingle('LineItem', ['contribution_id' => $contribution['id']]);
1070 $this->assertEquals(1000, $lineItem['line_total']);
1071 $this->assertEquals(100, $lineItem['tax_amount']);
1072
1073 // CRM-20423: Upon simple submit of 'Edit Contribution' form ensure that total amount is same
1074 $form->testSubmit([
1075 'id' => $contribution['id'],
1076 'financial_type_id' => 3,
1077 'contact_id' => $this->_individualId,
1078 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
1079 'contribution_status_id' => 1,
1080 ], CRM_Core_Action::UPDATE);
1081
1082 $contribution = $this->callAPISuccessGetSingle('Contribution', ['contact_id' => $this->_individualId]);
1083 // Check if total amount is unchanged
1084 $this->assertEquals(1100, $contribution['total_amount']);
1085 }
1086
1087 /**
1088 * Test the submit function for FT without tax.
1089 *
1090 * @throws \CRM_Core_Exception
1091 * @throws \CiviCRM_API3_Exception
1092 * @throws \Civi\Payment\Exception\PaymentProcessorException
1093 */
1094 public function testSubmitWithOutSaleTax() {
1095 $this->enableTaxAndInvoicing();
1096 $this->relationForFinancialTypeWithFinancialAccount($this->_financialTypeId);
1097 $form = new CRM_Contribute_Form_Contribution();
1098
1099 $form->testSubmit([
1100 'total_amount' => 100,
1101 'financial_type_id' => 3,
1102 'contact_id' => $this->_individualId,
1103 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
1104 'contribution_status_id' => 1,
1105 'price_set_id' => 0,
1106 ], CRM_Core_Action::ADD);
1107 $contribution = $this->callAPISuccessGetSingle('Contribution',
1108 [
1109 'contact_id' => $this->_individualId,
1110 'return' => ['tax_amount', 'total_amount'],
1111 ]
1112 );
1113 $this->assertEquals(100, $contribution['total_amount']);
1114 $this->assertEquals(NULL, $contribution['tax_amount']);
1115 $this->callAPISuccessGetCount('FinancialTrxn', [], 1);
1116 $this->callAPISuccessGetCount('FinancialItem', [], 1);
1117 $lineItem = $this->callAPISuccessGetSingle('LineItem', [
1118 'contribution_id' => $contribution['id'],
1119 'return' => ['line_total', 'tax_amount'],
1120 ]);
1121 $this->assertEquals(100, $lineItem['line_total']);
1122 $this->assertEquals(0.00, $lineItem['tax_amount']);
1123 }
1124
1125 /**
1126 * Create a contribution & then edit it via backoffice form, checking tax with: default price_set
1127 *
1128 * @param string $thousandSeparator
1129 *
1130 * @dataProvider getThousandSeparators
1131 *
1132 * @throws \Exception
1133 */
1134 public function testReSubmitSaleTax($thousandSeparator) {
1135 $this->setCurrencySeparators($thousandSeparator);
1136 $this->enableTaxAndInvoicing();
1137 $this->relationForFinancialTypeWithFinancialAccount($this->_financialTypeId);
1138 list($form, $contribution) = $this->doInitialSubmit();
1139 $this->assertEquals(11000, $contribution['total_amount']);
1140 $this->assertEquals(1000, $contribution['tax_amount']);
1141 $this->assertEquals(11000, $contribution['net_amount']);
1142
1143 $mut = new CiviMailUtils($this, TRUE);
1144 // Testing here if when we edit something trivial like adding a check_number tax, net, total amount stay the same:
1145 $form->testSubmit([
1146 'id' => $contribution['id'],
1147 'tax_amount' => $contribution['tax_amount'],
1148 'financial_type_id' => $contribution['financial_type_id'],
1149 'receive_date' => $contribution['receive_date'],
1150 'payment_instrument_id' => $contribution['payment_instrument_id'],
1151 'price_set_id' => 0,
1152 'check_number' => 12345,
1153 'contribution_status_id' => 1,
1154 'is_email_receipt' => 1,
1155 'from_email_address' => 'demo@example.com',
1156 ], CRM_Core_Action::UPDATE);
1157 $contribution = $this->callAPISuccessGetSingle('Contribution',
1158 [
1159 'contribution_id' => 1,
1160 'return' => ['tax_amount', 'total_amount', 'net_amount', 'financial_type_id', 'receive_date', 'payment_instrument_id'],
1161 ]
1162 );
1163 $this->assertEquals(11000, $contribution['total_amount']);
1164 $this->assertEquals(1000, $contribution['tax_amount']);
1165 $this->assertEquals(11000, $contribution['net_amount']);
1166
1167 $strings = [
1168 'Total Tax Amount : $ ' . $this->formatMoneyInput(1000.00),
1169 'Total Amount : $ ' . $this->formatMoneyInput(11000.00),
1170 'Date Received: April 21st, 2015',
1171 'Paid By: Check',
1172 'Check Number: 12345',
1173 ];
1174
1175 $mut->checkMailLog($strings);
1176 $this->callAPISuccessGetCount('FinancialTrxn', [], 3);
1177 $items = $this->callAPISuccess('FinancialItem', 'get', ['sequential' => 1])['values'];
1178 $this->assertEquals(2, count($items));
1179 $this->assertEquals('Contribution Amount', $items[0]['description']);
1180 $this->assertEquals('Sales Tax', $items[1]['description']);
1181
1182 $this->assertEquals(10000, $items[0]['amount']);
1183 $this->assertEquals(1000, $items[1]['amount']);
1184 }
1185
1186 /**
1187 * Create a contribution & then edit it via backoffice form, checking tax with: default price_set
1188 *
1189 * @param string $thousandSeparator
1190 *
1191 * @dataProvider getThousandSeparators
1192 *
1193 * @throws \Exception
1194 */
1195 public function testReSubmitSaleTaxAlteredAmount($thousandSeparator) {
1196 $this->setCurrencySeparators($thousandSeparator);
1197 $this->enableTaxAndInvoicing();
1198 $this->relationForFinancialTypeWithFinancialAccount($this->_financialTypeId);
1199 list($form, $contribution) = $this->doInitialSubmit();
1200
1201 $mut = new CiviMailUtils($this, TRUE);
1202 // Testing here if when we edit something trivial like adding a check_number tax, net, total amount stay the same:
1203 $form->testSubmit([
1204 'id' => $contribution['id'],
1205 'total_amount' => $this->formatMoneyInput(20000),
1206 'tax_amount' => $this->formatMoneyInput(2000),
1207 'financial_type_id' => $contribution['financial_type_id'],
1208 'receive_date' => $contribution['receive_date'],
1209 'payment_instrument_id' => $contribution['payment_instrument_id'],
1210 'price_set_id' => 0,
1211 'check_number' => 12345,
1212 'contribution_status_id' => 1,
1213 'is_email_receipt' => 1,
1214 'from_email_address' => 'demo@example.com',
1215 ], CRM_Core_Action::UPDATE);
1216 $contribution = $this->callAPISuccessGetSingle('Contribution',
1217 [
1218 'contribution_id' => 1,
1219 'return' => ['tax_amount', 'total_amount', 'net_amount', 'financial_type_id', 'receive_date', 'payment_instrument_id'],
1220 ]
1221 );
1222 $this->assertEquals(22000, $contribution['total_amount']);
1223 $this->assertEquals(2000, $contribution['tax_amount']);
1224 $this->assertEquals(22000, $contribution['net_amount']);
1225
1226 $strings = [
1227 'Total Tax Amount : $ ' . $this->formatMoneyInput(2000),
1228 'Total Amount : $ ' . $this->formatMoneyInput(22000.00),
1229 'Date Received: April 21st, 2015',
1230 'Paid By: Check',
1231 'Check Number: 12345',
1232 ];
1233
1234 $mut->checkMailLog($strings);
1235 $this->callAPISuccessGetCount('FinancialTrxn', [], 4);
1236 $items = $this->callAPISuccess('FinancialItem', 'get', ['sequential' => 1]);
1237 $this->assertEquals(4, $items['count']);
1238 $this->assertEquals('Contribution Amount', $items['values'][0]['description']);
1239 $this->assertEquals('Sales Tax', $items['values'][1]['description']);
1240 $this->assertEquals('Contribution Amount', $items['values'][0]['description']);
1241 $this->assertEquals('Sales Tax', $items['values'][1]['description']);
1242
1243 $this->assertEquals(10000, $items['values'][0]['amount']);
1244 $this->assertEquals(1000, $items['values'][1]['amount']);
1245 $this->assertEquals(10000, $items['values'][2]['amount']);
1246 $this->assertEquals(1000, $items['values'][3]['amount']);
1247 }
1248
1249 /**
1250 * Do the first contributions, in preparation for an edit-submit.
1251 *
1252 * @return array
1253 *
1254 * @throws \Exception
1255 */
1256 protected function doInitialSubmit() {
1257 $form = new CRM_Contribute_Form_Contribution();
1258
1259 $form->testSubmit([
1260 'total_amount' => $this->formatMoneyInput(10000),
1261 'financial_type_id' => $this->_financialTypeId,
1262 'receive_date' => '2015-04-21 00:00:00',
1263 'contact_id' => $this->_individualId,
1264 'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
1265 'contribution_status_id' => 1,
1266 'price_set_id' => 0,
1267 ], CRM_Core_Action::ADD);
1268 $contribution = $this->callAPISuccessGetSingle('Contribution',
1269 [
1270 'contribution_id' => 1,
1271 'return' => [
1272 'tax_amount',
1273 'total_amount',
1274 'net_amount',
1275 'financial_type_id',
1276 'receive_date',
1277 'payment_instrument_id',
1278 ],
1279 ]
1280 );
1281 $this->assertEquals(11000, $contribution['total_amount']);
1282 $this->assertEquals(1000, $contribution['tax_amount']);
1283 $this->assertEquals(11000, $contribution['net_amount']);
1284 return [$form, $contribution];
1285 }
1286
1287 /**
1288 * function to test card_type and pan truncation.
1289 */
1290 public function testCardTypeAndPanTruncation() {
1291 $form = new CRM_Contribute_Form_Contribution();
1292 $form->testSubmit(
1293 [
1294 'total_amount' => 100,
1295 'financial_type_id' => 3,
1296 'contact_id' => $this->_individualId,
1297 'payment_instrument_id' => array_search('Credit Card', $this->paymentInstruments),
1298 'contribution_status_id' => 1,
1299 'credit_card_type' => 'Visa',
1300 'pan_truncation' => 4567,
1301 'price_set_id' => 0,
1302 ],
1303 CRM_Core_Action::ADD
1304 );
1305 $contribution = $this->callAPISuccessGetSingle('Contribution',
1306 [
1307 'contact_id' => $this->_individualId,
1308 'return' => ['id'],
1309 ]
1310 );
1311 $lastFinancialTrxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contribution['id'], 'DESC');
1312 $financialTrxn = $this->callAPISuccessGetSingle(
1313 'FinancialTrxn',
1314 [
1315 'id' => $lastFinancialTrxnId['financialTrxnId'],
1316 'return' => ['card_type_id.label', 'pan_truncation'],
1317 ]
1318 );
1319 $this->assertEquals(CRM_Utils_Array::value('card_type_id.label', $financialTrxn), 'Visa');
1320 $this->assertEquals(CRM_Utils_Array::value('pan_truncation', $financialTrxn), 4567);
1321 }
1322
1323 /**
1324 * Check payment processor is correctly assigned for a contribution page.
1325 *
1326 * @throws \CRM_Core_Exception
1327 * @throws \CRM_Contribute_Exception_InactiveContributionPageException
1328 */
1329 public function testContributionBasePreProcess() {
1330 //Create contribution page with only pay later enabled.
1331 $params = [
1332 'title' => "Test Contribution Page",
1333 'financial_type_id' => 1,
1334 'currency' => 'NZD',
1335 'goal_amount' => 100,
1336 'is_pay_later' => 1,
1337 'pay_later_text' => 'Send check',
1338 'is_monetary' => TRUE,
1339 'is_active' => TRUE,
1340 'is_email_receipt' => TRUE,
1341 'receipt_from_email' => 'yourconscience@donate.com',
1342 'receipt_from_name' => 'Ego Freud',
1343 ];
1344
1345 $page1 = $this->callAPISuccess("contribution_page", 'create', $params);
1346
1347 //Execute CRM_Contribute_Form_ContributionBase preProcess
1348 //and check the assignment of payment processors
1349 $form = new CRM_Contribute_Form_ContributionBase();
1350 $form->controller = new CRM_Core_Controller();
1351 $form->set('id', $page1['id']);
1352 $_REQUEST['id'] = $page1['id'];
1353
1354 $form->preProcess();
1355 $this->assertEquals($form->_paymentProcessor['name'], 'pay_later');
1356
1357 //Disable all the payment processor for the contribution page.
1358 $params['is_pay_later'] = 0;
1359 $page2 = $this->callAPISuccess("contribution_page", 'create', $params);
1360
1361 //Assert an exception is thrown on loading the contribution page.
1362 $form = new CRM_Contribute_Form_ContributionBase();
1363 $form->controller = new CRM_Core_Controller();
1364 $_REQUEST['id'] = $page2['id'];
1365 $form->set('id', $page2['id']);
1366 try {
1367 $form->preProcess();
1368 }
1369 catch (CRM_Core_Exception $e) {
1370 $this->assertContains("A payment processor configured for this page might be disabled (contact the site administrator for assistance).", $e->getMessage());
1371 return;
1372 }
1373 $this->fail('Exception was expected');
1374 }
1375
1376 /**
1377 * function to test card_type and pan truncation.
1378 */
1379 public function testCardTypeAndPanTruncationLiveMode() {
1380 $visaID = CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_FinancialTrxn', 'card_type_id', 'Visa');
1381 $form = new CRM_Contribute_Form_Contribution();
1382 $form->_mode = 'Live';
1383 $form->testSubmit(
1384 [
1385 'total_amount' => 50,
1386 'financial_type_id' => 1,
1387 'contact_id' => $this->_individualId,
1388 'credit_card_number' => 4444333322221111,
1389 'payment_instrument_id' => array_search('Credit Card', $this->paymentInstruments),
1390 'cvv2' => 123,
1391 'credit_card_exp_date' => [
1392 'M' => 9,
1393 'Y' => date('Y', strtotime('+5 years')),
1394 ],
1395 'credit_card_type' => 'Visa',
1396 'billing_first_name' => 'Junko',
1397 'billing_middle_name' => '',
1398 'billing_last_name' => 'Adams',
1399 'billing_street_address-5' => '790L Lincoln St S',
1400 'billing_city-5' => 'Maryknoll',
1401 'billing_state_province_id-5' => 1031,
1402 'billing_postal_code-5' => 10545,
1403 'billing_country_id-5' => 1228,
1404 'frequency_interval' => 1,
1405 'frequency_unit' => 'month',
1406 'installments' => '',
1407 'hidden_AdditionalDetail' => 1,
1408 'hidden_Premium' => 1,
1409 'from_email_address' => '"civi45" <civi45@civicrm.com>',
1410 'receipt_date' => '',
1411 'receipt_date_time' => '',
1412 'payment_processor_id' => $this->paymentProcessorID,
1413 'currency' => 'USD',
1414 'source' => 'bob sled race',
1415 ],
1416 CRM_Core_Action::ADD
1417 );
1418 $contribution = $this->callAPISuccessGetSingle('Contribution', ['contact_id' => $this->_individualId]);
1419 $lastFinancialTrxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contribution['id'], 'DESC');
1420 $financialTrxn = $this->callAPISuccessGetSingle(
1421 'FinancialTrxn',
1422 [
1423 'id' => $lastFinancialTrxnId['financialTrxnId'],
1424 'return' => ['card_type_id', 'pan_truncation'],
1425 ]
1426 );
1427 $this->assertEquals($visaID, $financialTrxn['card_type_id']);
1428 $this->assertEquals(1111, $financialTrxn['pan_truncation']);
1429 }
1430
1431 /**
1432 * CRM-21711 Test that custom fields on relevant memberships get updated wehn updating multiple memberships
1433 */
1434 public function testCustomFieldsOnMembershipGetUpdated() {
1435 $contactID = $this->individualCreate();
1436 $contactID1 = $this->organizationCreate();
1437 $contactID2 = $this->organizationCreate();
1438
1439 // create membership types
1440 $membershipTypeOne = civicrm_api3('membership_type', 'create', [
1441 'domain_id' => 1,
1442 'name' => "One",
1443 'member_of_contact_id' => $contactID1,
1444 'duration_unit' => "year",
1445 'minimum_fee' => 50,
1446 'duration_interval' => 1,
1447 'period_type' => "fixed",
1448 'fixed_period_start_day' => "101",
1449 'fixed_period_rollover_day' => "1231",
1450 'financial_type_id' => 1,
1451 'weight' => 50,
1452 'is_active' => 1,
1453 'visibility' => "Public",
1454 ]);
1455
1456 $membershipTypeTwo = civicrm_api3('membership_type', 'create', [
1457 'domain_id' => 1,
1458 'name' => "Two",
1459 'member_of_contact_id' => $contactID2,
1460 'duration_unit' => "year",
1461 'minimum_fee' => 50,
1462 'duration_interval' => 1,
1463 'period_type' => "fixed",
1464 'fixed_period_start_day' => "101",
1465 'fixed_period_rollover_day' => "1231",
1466 'financial_type_id' => 1,
1467 'weight' => 51,
1468 'is_active' => 1,
1469 'visibility' => "Public",
1470 ]);
1471
1472 //create custom Fields
1473 $membershipCustomFieldsGroup = civicrm_api3('CustomGroup', 'create', [
1474 'title' => "Custom Fields on Membership",
1475 'extends' => "Membership",
1476 ]);
1477
1478 $membershipCustomField = civicrm_api3('CustomField', 'create', [
1479 "custom_group_id" => $membershipCustomFieldsGroup['id'],
1480 "name" => "my_membership_custom_field",
1481 "label" => "Membership Custom Field",
1482 "data_type" => "String",
1483 "html_type" => "Text",
1484 "is_active" => "1",
1485 "is_view" => "0",
1486 "text_length" => "255",
1487 ]);
1488
1489 // create profile
1490 $membershipCustomFieldsProfile = civicrm_api3('UFGroup', 'create', [
1491 "is_active" => "1",
1492 "group_type" => "Membership,Individual",
1493 "title" => "Membership Custom Fields",
1494 "add_captcha" => "0",
1495 "is_map" => "0",
1496 "is_edit_link" => "0",
1497 "is_uf_link" => "0",
1498 "is_update_dupe" => "0",
1499 ]);
1500
1501 // add custom fields to profile
1502 $membershipCustomFieldsProfileFields = civicrm_api3('UFField', 'create', [
1503 "uf_group_id" => $membershipCustomFieldsProfile['id'],
1504 "field_name" => "custom_" . $membershipCustomField['id'],
1505 "is_active" => "1",
1506 "visibility" => "User and User Admin Only",
1507 "in_selector" => "0",
1508 "is_searchable" => "0",
1509 "label" => "custom text field on membership",
1510 "field_type" => "Membership",
1511 ]);
1512
1513 $contribPage = civicrm_api3('ContributionPage', 'create', [
1514 "title" => "Membership",
1515 "financial_type_id" => 1,
1516 'financial_account_id' => 1,
1517 "is_credit_card_only" => "0",
1518 "is_monetary" => "0",
1519 "is_recur" => "0",
1520 "is_confirm_enabled" => "1",
1521 "is_recur_interval" => "0",
1522 "is_recur_installments" => "0",
1523 "adjust_recur_start_date" => "0",
1524 "is_pay_later" => "1",
1525 "pay_later_text" => "I will send payment by check",
1526 "is_partial_payment" => "0",
1527 "is_allow_other_amount" => "0",
1528 "is_email_receipt" => "0",
1529 "is_active" => "1",
1530 "amount_block_is_active" => "0",
1531 "currency" => "USD",
1532 "is_share" => "0",
1533 "is_billing_required" => "0",
1534 "contribution_type_id" => "2",
1535 'is_allow_other_amount' => 1,
1536 'min_amount' => 10,
1537 'max_amount' => 1000,
1538 ]);
1539 $contribPage1 = $contribPage['id'];
1540
1541 //create price set with two options for the two different memberships
1542 $priceSet = civicrm_api3('PriceSet', 'create', [
1543 'title' => "Two Membership Type Checkbox",
1544 'extends' => "CiviMember",
1545 'is_active' => 1,
1546 "financial_type_id" => "1",
1547 "is_quick_config" => "0",
1548 "is_reserved" => "0",
1549 "entity" => ["civicrm_contribution_page" => [$contribPage1]],
1550 ]);
1551
1552 $priceField = civicrm_api3('PriceField', 'create', [
1553 "price_set_id" => $priceSet['id'],
1554 "name" => "mt",
1555 "label" => "Membership Types",
1556 "html_type" => "CheckBox",
1557 "is_enter_qty" => "0",
1558 "weight" => "1",
1559 "is_display_amounts" => "1",
1560 "options_per_line" => "1",
1561 "is_active" => "1",
1562 "is_required" => "0",
1563 "visibility_id" => "1",
1564 ]);
1565
1566 $priceFieldOption1 = civicrm_api3('PriceFieldValue', 'create', [
1567 "price_field_id" => $priceField['id'],
1568 "name" => "membership_type_one",
1569 "label" => "Membership Type One",
1570 "amount" => "50",
1571 "weight" => "1",
1572 "membership_type_id" => $membershipTypeOne['id'],
1573 "membership_num_terms" => "1",
1574 "is_default" => "0",
1575 "is_active" => "1",
1576 "financial_type_id" => "1",
1577 "non_deductible_amount" => "0.00",
1578 "contribution_type_id" => "2",
1579 ]);
1580
1581 $priceFieldOption2 = civicrm_api3('PriceFieldValue', 'create', [
1582 "price_field_id" => $priceField['id'],
1583 "name" => "membership_type_two",
1584 "label" => "Membership Type Two",
1585 "amount" => "50",
1586 "weight" => "1",
1587 "membership_type_id" => $membershipTypeTwo['id'],
1588 "membership_num_terms" => "1",
1589 "is_default" => "0",
1590 "is_active" => "1",
1591 "financial_type_id" => "1",
1592 "non_deductible_amount" => "0.00",
1593 "contribution_type_id" => "2",
1594 ]);
1595
1596 // assign profile with custom fields to contribution page
1597 $profile = civicrm_api3('UFJoin', 'create', [
1598 'module' => "CiviContribute",
1599 'weight' => "1",
1600 'uf_group_id' => $membershipCustomFieldsProfile['id'],
1601 "entity_table" => "civicrm_contribution_page",
1602 "entity_id" => $contribPage1,
1603 ]);
1604
1605 $form = new CRM_Contribute_Form_Contribution_Confirm();
1606 $form->_params = [
1607 'id' => $contribPage1,
1608 "qfKey" => "donotcare",
1609 "custom_{$membershipCustomField['id']}" => "Hello",
1610 "email-5" => "admin@example.com",
1611 "priceSetId" => $priceSet['id'],
1612 'price_set_id' => $priceSet['id'],
1613 "price_" . $priceField['id'] => [$priceFieldOption1['id'] => 1, $priceFieldOption2['id'] => 1],
1614 "invoiceID" => "9a6f7b49358dc31c3604e463b225c5be",
1615 "email" => "admin@example.com",
1616 "currencyID" => "USD",
1617 'description' => "Membership Contribution",
1618 'contact_id' => $contactID,
1619 'skipLineItem' => 0,
1620 'email-5' => 'test@test.com',
1621 'amount' => 100,
1622 'tax_amount' => 0.00,
1623 'is_pay_later' => 1,
1624 'is_quick_config' => 1,
1625 ];
1626 $form->submit($form->_params);
1627 $membership1 = civicrm_api3('Membership', 'getsingle', [
1628 'contact_id' => $contactID,
1629 'membership_type_id' => $membershipTypeOne['id'],
1630 ]);
1631 $this->assertEquals("Hello", $membership1["custom_{$membershipCustomField['id']}"]);
1632
1633 $membership2 = civicrm_api3('Membership', 'getsingle', [
1634 'contact_id' => $contactID,
1635 'membership_type_id' => $membershipTypeTwo['id'],
1636 ]);
1637 $this->assertEquals("Hello", $membership2["custom_{$membershipCustomField['id']}"]);
1638 }
1639
1640 /**
1641 * Test non-membership donation on a contribution page
1642 * using membership priceset.
1643 */
1644 public function testDonationOnMembershipPagePriceset() {
1645 $contactID = $this->individualCreate();
1646 $this->createPriceSetWithPage();
1647 $form = new CRM_Contribute_Form_Contribution_Confirm();
1648 $form->controller = new CRM_Core_Controller();
1649 $form->_params = [
1650 'id' => $this->_ids['contribution_page'],
1651 "qfKey" => "donotcare",
1652 "priceSetId" => $this->_ids['price_set'],
1653 'price_set_id' => $this->_ids['price_set'],
1654 "price_" . $this->_ids['price_field'][0] => $this->_ids['price_field_value']['cont'],
1655 "invoiceID" => "9a6f7b49358dc31c3604e463b225c5be",
1656 "email" => "admin@example.com",
1657 "currencyID" => "USD",
1658 'description' => "Membership Contribution",
1659 'contact_id' => $contactID,
1660 'select_contact_id' => $contactID,
1661 'useForMember' => 1,
1662 'skipLineItem' => 0,
1663 'email-5' => 'test@test.com',
1664 'amount' => 10,
1665 'tax_amount' => NULL,
1666 'is_pay_later' => 1,
1667 'is_quick_config' => 1,
1668 ];
1669 $form->submit($form->_params);
1670
1671 $contribution = $this->callAPISuccessGetSingle('Contribution', [
1672 'contact_id' => $contactID,
1673 ]);
1674 //Check no membership is created.
1675 $this->callAPIFailure('Membership', 'getsingle', [
1676 'contact_id' => $contactID,
1677 ]);
1678 $this->contributionDelete($contribution['id']);
1679
1680 //Choose Membership Priceset
1681 $form->_params["price_{$this->_ids['price_field'][0]}"] = $this->_ids['price_field_value'][0];
1682 $form->_params["amount"] = 20;
1683 $form->submit($form->_params);
1684
1685 $contribution = $this->callAPISuccessGetSingle('Contribution', [
1686 'contact_id' => $contactID,
1687 ]);
1688 //Check membership is created for the contact.
1689 $membership = $this->callAPISuccessGetSingle('Membership', [
1690 'contact_id' => $contactID,
1691 ]);
1692 $membershipPayment = $this->callAPISuccessGetSingle('MembershipPayment', [
1693 'contribution_id' => $contribution['id'],
1694 ]);
1695 $this->assertEquals($membershipPayment['membership_id'], $membership['id']);
1696 $this->membershipDelete($membership['id']);
1697 }
1698
1699 /**
1700 * Test no warnings or errors during preProcess when editing.
1701 */
1702 public function testPreProcessContributionEdit() {
1703 // Simulate a contribution in pending status
1704 $contribution = $this->callAPISuccess(
1705 'Contribution',
1706 'create',
1707 array_merge($this->_params, ['contribution_status_id' => 'Pending'])
1708 );
1709
1710 // set up the form to edit the contribution and call preProcess
1711 $form = $this->getFormObject('CRM_Contribute_Form_Contribution');
1712 $_REQUEST['cid'] = $this->_individualId;
1713 $_REQUEST['id'] = $contribution['id'];
1714 $form->_action = CRM_Core_Action::UPDATE;
1715 $form->preProcess();
1716
1717 // Check something while we're here
1718 $this->assertEquals($contribution['id'], $form->_values['contribution_id']);
1719
1720 unset($_REQUEST['cid']);
1721 unset($_REQUEST['id']);
1722 }
1723
1724 }