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