Merge pull request #15944 from magnolia61/Sort_CMS_tables_alphabetically
[civicrm-core.git] / tests / phpunit / api / v3 / ContributionPageTest.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_recur* functions
14 *
15 * @package CiviCRM_APIv3
16 * @subpackage API_Contribution
17 * @group headless
18 */
19 class api_v3_ContributionPageTest extends CiviUnitTestCase {
20 protected $testAmount = 34567;
21 protected $params;
22 protected $id = 0;
23 protected $contactIds = [];
24 protected $_entity = 'contribution_page';
25 protected $contribution_result = NULL;
26 protected $_priceSetParams = [];
27 protected $_membershipBlockAmount = 2;
28 /**
29 * Payment processor details.
30 * @var array
31 */
32 protected $_paymentProcessor = [];
33
34 /**
35 * @var array
36 * - contribution_page
37 * - price_set
38 * - price_field
39 * - price_field_value
40 */
41 protected $_ids = [];
42
43 public $DBResetRequired = TRUE;
44
45 /**
46 * Setup for test.
47 *
48 * @throws \CRM_Core_Exception
49 */
50 public function setUp() {
51 parent::setUp();
52 $this->contactIds[] = $this->individualCreate();
53 $this->params = [
54 'title' => 'Test Contribution Page',
55 'financial_type_id' => 1,
56 'currency' => 'NZD',
57 'goal_amount' => $this->testAmount,
58 'is_pay_later' => 1,
59 'pay_later_text' => 'Send check',
60 'is_monetary' => TRUE,
61 'is_email_receipt' => TRUE,
62 'receipt_from_email' => 'yourconscience@donate.com',
63 'receipt_from_name' => 'Ego Freud',
64 ];
65
66 $this->_priceSetParams = [
67 'is_quick_config' => 1,
68 'extends' => 'CiviContribute',
69 'financial_type_id' => 'Donation',
70 'title' => 'my Page',
71 ];
72 }
73
74 /**
75 * Tear down after test.
76 *
77 * @throws \CRM_Core_Exception
78 * @throws \CiviCRM_API3_Exception
79 */
80 public function tearDown() {
81 foreach ($this->contactIds as $id) {
82 $this->callAPISuccess('contact', 'delete', ['id' => $id]);
83 }
84 $this->quickCleanUpFinancialEntities();
85 parent::tearDown();
86 }
87
88 /**
89 * Test creating a contribution page.
90 *
91 * @param int $version
92 *
93 * @dataProvider versionThreeAndFour
94 * @throws \CRM_Core_Exception
95 */
96 public function testCreateContributionPage($version) {
97 $this->_apiversion = $version;
98 $result = $this->callAPIAndDocument($this->_entity, 'create', $this->params, __FUNCTION__, __FILE__);
99 $this->assertEquals(1, $result['count']);
100 $this->assertNotNull($result['values'][$result['id']]['id']);
101 $this->getAndCheck($this->params, $result['id'], $this->_entity);
102 }
103
104 /**
105 * Test getting a contribution page.
106 *
107 * @param int $version
108 *
109 * @dataProvider versionThreeAndFour
110 * @throws \CRM_Core_Exception
111 */
112 public function testGetBasicContributionPage($version) {
113 $this->_apiversion = $version;
114 $createResult = $this->callAPISuccess($this->_entity, 'create', $this->params);
115 $this->id = $createResult['id'];
116 $getParams = [
117 'currency' => 'NZD',
118 'financial_type_id' => 1,
119 ];
120 $getResult = $this->callAPIAndDocument($this->_entity, 'get', $getParams, __FUNCTION__, __FILE__);
121 $this->assertEquals(1, $getResult['count']);
122 }
123
124 /**
125 * Test get with amount as a parameter.
126 *
127 * @throws \CRM_Core_Exception
128 */
129 public function testGetContributionPageByAmount() {
130 $createResult = $this->callAPISuccess($this->_entity, 'create', $this->params);
131 $this->id = $createResult['id'];
132 $getParams = [
133 // 3456
134 'amount' => '' . $this->testAmount,
135 'currency' => 'NZD',
136 'financial_type_id' => 1,
137 ];
138 $getResult = $this->callAPISuccess($this->_entity, 'get', $getParams);
139 $this->assertEquals(1, $getResult['count']);
140 }
141
142 /**
143 * Test page deletion.
144 *
145 * @param int $version
146 *
147 * @dataProvider versionThreeAndFour
148 * @throws \CRM_Core_Exception
149 */
150 public function testDeleteContributionPage($version) {
151 $this->_apiversion = $version;
152 $createResult = $this->callAPISuccess($this->_entity, 'create', $this->params);
153 $deleteParams = ['id' => $createResult['id']];
154 $this->callAPIAndDocument($this->_entity, 'delete', $deleteParams, __FUNCTION__, __FILE__);
155 $checkDeleted = $this->callAPISuccess($this->_entity, 'get', []);
156 $this->assertEquals(0, $checkDeleted['count']);
157 }
158
159 /**
160 * Test getfields function.
161 *
162 * @throws \CRM_Core_Exception
163 */
164 public function testGetFieldsContributionPage() {
165 $result = $this->callAPISuccess($this->_entity, 'getfields', ['action' => 'create']);
166 $this->assertEquals(12, $result['values']['start_date']['type']);
167 }
168
169 /**
170 * Test form submission with basic price set.
171 *
172 * @throws \CRM_Core_Exception
173 */
174 public function testSubmit() {
175 $this->setUpContributionPage();
176 $submitParams = $this->getBasicSubmitParams();
177
178 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
179 $contribution = $this->callAPISuccess('contribution', 'getsingle', ['contribution_page_id' => $this->_ids['contribution_page']]);
180 //assert non-deductible amount
181 $this->assertEquals(5.00, $contribution['non_deductible_amount']);
182 }
183
184 /**
185 * Test form submission with basic price set.
186 */
187 public function testSubmitZeroDollar() {
188 $this->setUpContributionPage();
189 $priceFieldID = reset($this->_ids['price_field']);
190 $submitParams = [
191 'price_' . $priceFieldID => $this->_ids['price_field_value']['cheapskate'],
192 'id' => (int) $this->_ids['contribution_page'],
193 'amount' => 0,
194 'priceSetId' => $this->_ids['price_set'][0],
195 'payment_processor_id' => '',
196 ];
197
198 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
199 $contribution = $this->callAPISuccess('contribution', 'getsingle', ['contribution_page_id' => $this->_ids['contribution_page']]);
200
201 $this->assertEquals($this->formatMoneyInput(0), $contribution['non_deductible_amount']);
202 $this->assertEquals($this->formatMoneyInput(0), $contribution['total_amount']);
203 }
204
205 /**
206 * Test form submission with billing first & last name where the contact does NOT
207 * otherwise have one.
208 *
209 * @throws \CRM_Core_Exception
210 */
211 public function testSubmitNewBillingNameData() {
212 $this->setUpContributionPage();
213 $contact = $this->callAPISuccess('Contact', 'create', ['contact_type' => 'Individual', 'email' => 'wonderwoman@amazon.com']);
214 $priceFieldID = reset($this->_ids['price_field']);
215 $priceFieldValueID = reset($this->_ids['price_field_value']);
216 $submitParams = [
217 'price_' . $priceFieldID => $priceFieldValueID,
218 'id' => (int) $this->_ids['contribution_page'],
219 'amount' => 10,
220 'billing_first_name' => 'Wonder',
221 'billing_last_name' => 'Woman',
222 'contactID' => $contact['id'],
223 'email' => 'wonderwoman@amazon.com',
224 ];
225
226 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
227 $contact = $this->callAPISuccess('Contact', 'get', [
228 'id' => $contact['id'],
229 'return' => [
230 'first_name',
231 'last_name',
232 'sort_name',
233 'display_name',
234 ],
235 ]);
236 $this->assertEquals([
237 'first_name' => 'Wonder',
238 'last_name' => 'Woman',
239 'display_name' => 'Wonder Woman',
240 'sort_name' => 'Woman, Wonder',
241 'id' => $contact['id'],
242 'contact_id' => $contact['id'],
243 ], $contact['values'][$contact['id']]);
244
245 }
246
247 /**
248 * Test form submission with billing first & last name where the contact does
249 * otherwise have one and should not be overwritten.
250 */
251 public function testSubmitNewBillingNameDoNotOverwrite() {
252 $this->setUpContributionPage();
253 $contact = $this->callAPISuccess('Contact', 'create', [
254 'contact_type' => 'Individual',
255 'email' => 'wonderwoman@amazon.com',
256 'first_name' => 'Super',
257 'last_name' => 'Boy',
258 ]);
259 $priceFieldID = reset($this->_ids['price_field']);
260 $priceFieldValueID = reset($this->_ids['price_field_value']);
261 $submitParams = [
262 'price_' . $priceFieldID => $priceFieldValueID,
263 'id' => (int) $this->_ids['contribution_page'],
264 'amount' => 10,
265 'billing_first_name' => 'Wonder',
266 'billing_last_name' => 'Woman',
267 'contactID' => $contact['id'],
268 'email' => 'wonderwoman@amazon.com',
269 ];
270
271 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
272 $contact = $this->callAPISuccess('Contact', 'get', [
273 'id' => $contact['id'],
274 'return' => [
275 'first_name',
276 'last_name',
277 'sort_name',
278 'display_name',
279 ],
280 ]);
281 $this->assertEquals([
282 'first_name' => 'Super',
283 'last_name' => 'Boy',
284 'display_name' => 'Super Boy',
285 'sort_name' => 'Boy, Super',
286 'id' => $contact['id'],
287 'contact_id' => $contact['id'],
288 ], $contact['values'][$contact['id']]);
289
290 }
291
292 /**
293 * Test process with instant payment when more than one configured for the page.
294 *
295 * CRM-16923
296 *
297 * @throws \CiviCRM_API3_Exception
298 * @throws \CRM_Core_Exception
299 */
300 public function testSubmitRecurMultiProcessorInstantPayment() {
301 $this->setUpContributionPage();
302 $this->setupPaymentProcessor();
303 $paymentProcessor2ID = $this->paymentProcessorCreate([
304 'payment_processor_type_id' => 'Dummy',
305 'name' => 'processor 2',
306 'class_name' => 'Payment_Dummy',
307 'billing_mode' => 1,
308 ]);
309 $dummyPP = Civi\Payment\System::singleton()->getById($paymentProcessor2ID);
310 $dummyPP->setDoDirectPaymentResult([
311 'payment_status_id' => 1,
312 'trxn_id' => 'create_first_success',
313 'fee_amount' => .85,
314 ]);
315 $processor = $dummyPP->getPaymentProcessor();
316 $this->callAPISuccess('ContributionPage', 'create', [
317 'id' => $this->_ids['contribution_page'],
318 'payment_processor' => [$paymentProcessor2ID, $this->_ids['payment_processor']],
319 ]);
320
321 $priceFieldID = reset($this->_ids['price_field']);
322 $priceFieldValueID = reset($this->_ids['price_field_value']);
323 $submitParams = [
324 'price_' . $priceFieldID => $priceFieldValueID,
325 'id' => (int) $this->_ids['contribution_page'],
326 'amount' => 10,
327 'is_recur' => 1,
328 'frequency_interval' => 1,
329 'frequency_unit' => 'month',
330 'payment_processor_id' => $paymentProcessor2ID,
331 ];
332
333 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
334 $contribution = $this->callAPISuccess('contribution', 'getsingle', [
335 'contribution_page_id' => $this->_ids['contribution_page'],
336 'contribution_status_id' => 1,
337 ]);
338 $this->assertEquals('create_first_success', $contribution['trxn_id']);
339 $this->assertEquals(10, $contribution['total_amount']);
340 $this->assertEquals(.85, $contribution['fee_amount']);
341 $this->assertEquals(9.15, $contribution['net_amount']);
342 $this->_checkFinancialRecords([
343 'id' => $contribution['id'],
344 'total_amount' => $contribution['total_amount'],
345 'payment_instrument_id' => $processor['payment_instrument_id'],
346 ], 'online');
347 }
348
349 /**
350 * Test submit with a membership block in place.
351 *
352 * @throws \CRM_Core_Exception
353 */
354 public function testSubmitMembershipBlockNotSeparatePayment() {
355 $this->setUpMembershipContributionPage();
356 $submitParams = [
357 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
358 'id' => (int) $this->_ids['contribution_page'],
359 'amount' => 10,
360 'billing_first_name' => 'Billy',
361 'billing_middle_name' => 'Goat',
362 'billing_last_name' => 'Gruff',
363 'selectMembership' => $this->_ids['membership_type'][0],
364 ];
365
366 $this->callAPIAndDocument('ContributionPage', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL);
367 $contribution = $this->callAPISuccess('contribution', 'getsingle', ['contribution_page_id' => $this->_ids['contribution_page']]);
368 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', ['contribution_id' => $contribution['id']]);
369 $this->callAPISuccessGetSingle('LineItem', ['contribution_id' => $contribution['id'], 'entity_id' => $membershipPayment['id']]);
370 }
371
372 /**
373 * Test submit with a membership block in place works with renewal.
374 *
375 * @throws \CRM_Core_Exception
376 */
377 public function testSubmitMembershipBlockNotSeparatePaymentProcessorInstantRenew() {
378 $this->setUpMembershipContributionPage();
379 $dummyPP = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
380 $dummyPP->setDoDirectPaymentResult(['payment_status_id' => 1]);
381 $submitParams = [
382 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
383 'id' => (int) $this->_ids['contribution_page'],
384 'billing_first_name' => 'Billy',
385 'billing_middle_name' => 'Goat',
386 'billing_last_name' => 'Gruff',
387 'selectMembership' => $this->_ids['membership_type'][0],
388 'payment_processor_id' => 1,
389 'credit_card_number' => '4111111111111111',
390 'credit_card_type' => 'Visa',
391 'credit_card_exp_date' => ['M' => 9, 'Y' => 2040],
392 'cvv2' => 123,
393 ];
394
395 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
396 $contribution = $this->callAPISuccess('contribution', 'getsingle', ['contribution_page_id' => $this->_ids['contribution_page']]);
397 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', ['contribution_id' => $contribution['id']]);
398 $this->callAPISuccessGetCount('LineItem', [
399 'entity_table' => 'civicrm_membership',
400 'entity_id' => $membershipPayment['id'],
401 ], 1);
402
403 $submitParams['contact_id'] = $contribution['contact_id'];
404
405 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
406 $this->callAPISuccessGetCount('LineItem', [
407 'entity_table' => 'civicrm_membership',
408 'entity_id' => $membershipPayment['id'],
409 ], 2);
410 $membership = $this->callAPISuccessGetSingle('Membership', [
411 'id' => $membershipPayment['membership_id'],
412 'return' => ['end_date', 'join_date', 'start_date'],
413 ]);
414 $this->assertEquals(date('Y-m-d'), $membership['start_date']);
415 $this->assertEquals(date('Y-m-d'), $membership['join_date']);
416 $this->assertEquals(date('Y-m-d', strtotime('+ 2 year - 1 day')), $membership['end_date']);
417 }
418
419 /**
420 * Test submit with a membership block in place.
421 *
422 * @throws \CRM_Core_Exception
423 */
424 public function testSubmitMembershipBlockNotSeparatePaymentWithEmail() {
425 $mut = new CiviMailUtils($this, TRUE);
426 $this->setUpMembershipContributionPage();
427 $this->addProfile('supporter_profile', $this->_ids['contribution_page']);
428
429 $submitParams = [
430 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
431 'id' => (int) $this->_ids['contribution_page'],
432 'billing_first_name' => 'Billy',
433 'billing_middle_name' => 'Goat',
434 'billing_last_name' => 'Gruff',
435 'selectMembership' => $this->_ids['membership_type'][0],
436 'email-Primary' => 'billy-goat@the-bridge.net',
437 'payment_processor_id' => $this->_paymentProcessor['id'],
438 'credit_card_number' => '4111111111111111',
439 'credit_card_type' => 'Visa',
440 'credit_card_exp_date' => ['M' => 9, 'Y' => 2040],
441 'cvv2' => 123,
442 ];
443
444 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
445 $contribution = $this->callAPISuccess('contribution', 'getsingle', ['contribution_page_id' => $this->_ids['contribution_page']]);
446 $this->callAPISuccess('membership_payment', 'getsingle', ['contribution_id' => $contribution['id']]);
447 $mut->checkMailLog([
448 'Membership Type: General',
449 'Test Frontend title',
450 ]);
451 $mut->stop();
452 $mut->clearMessages();
453 }
454
455 /**
456 * Test submit with a membership block in place.
457 *
458 * @throws \Exception
459 */
460 public function testSubmitMembershipBlockNotSeparatePaymentZeroDollarsWithEmail() {
461 $mut = new CiviMailUtils($this, TRUE);
462 $this->_ids['membership_type'] = [$this->membershipTypeCreate(['minimum_fee' => 0])];
463 $this->setUpMembershipContributionPage();
464 $this->addProfile('supporter_profile', $this->_ids['contribution_page']);
465
466 $submitParams = [
467 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
468 'id' => (int) $this->_ids['contribution_page'],
469 'amount' => 0,
470 'billing_first_name' => 'Billy',
471 'billing_middle_name' => 'Goat',
472 'billing_last_name' => 'Gruffier',
473 'selectMembership' => $this->_ids['membership_type'][0],
474 'email-Primary' => 'billy-goat@the-new-bridge.net',
475 'payment_processor_id' => $this->params['payment_processor_id'],
476 ];
477
478 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
479 $contribution = $this->callAPISuccess('contribution', 'getsingle', ['contribution_page_id' => $this->_ids['contribution_page']]);
480 $this->callAPISuccess('membership_payment', 'getsingle', ['contribution_id' => $contribution['id']]);
481 //Assert only one mail is being sent.
482 $msgs = $mut->getAllMessages();
483 $this->assertCount(1, $msgs);
484
485 $mut->checkMailLog([
486 'Membership Type: General',
487 'Gruffier',
488 ], [
489 'Amount',
490 ]);
491 $mut->stop();
492 $mut->clearMessages();
493 }
494
495 /**
496 * Test submit with a pay later abnd check line item in mails.
497 *
498 * @throws \CRM_Core_Exception
499 */
500 public function testSubmitMembershipBlockIsSeparatePaymentPayLaterWithEmail() {
501 $mut = new CiviMailUtils($this, TRUE);
502 $this->setUpMembershipContributionPage();
503 $submitParams = [
504 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
505 'id' => (int) $this->_ids['contribution_page'],
506 'amount' => 10,
507 'billing_first_name' => 'Billy',
508 'billing_middle_name' => 'Goat',
509 'billing_last_name' => 'Gruff',
510 'is_pay_later' => 1,
511 'selectMembership' => $this->_ids['membership_type'][0],
512 'email-Primary' => 'billy-goat@the-bridge.net',
513 ];
514
515 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
516 $contribution = $this->callAPISuccess('contribution', 'getsingle', ['contribution_page_id' => $this->_ids['contribution_page']]);
517 $this->callAPISuccess('membership_payment', 'getsingle', ['contribution_id' => $contribution['id']]);
518 $mut->checkMailLog([
519 'Membership Amount -... $ 2.00',
520 ]);
521 $mut->stop();
522 $mut->clearMessages();
523 }
524
525 /**
526 * Test submit with a membership block in place.
527 *
528 * @throws \CRM_Core_Exception
529 */
530 public function testSubmitMembershipBlockIsSeparatePayment() {
531 $this->setUpMembershipContributionPage(TRUE);
532 $this->_ids['membership_type'] = [$this->membershipTypeCreate(['minimum_fee' => 2])];
533 $submitParams = [
534 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
535 'id' => (int) $this->_ids['contribution_page'],
536 'billing_first_name' => 'Billy',
537 'billing_middle_name' => 'Goat',
538 'billing_last_name' => 'Gruff',
539 'selectMembership' => $this->_ids['membership_type'][0],
540 'amount' => 10,
541 ];
542
543 $this->callAPISuccess('ContributionPage', 'submit', $submitParams);
544 $contributions = $this->callAPISuccess('contribution', 'get', ['contribution_page_id' => $this->_ids['contribution_page']]);
545 $this->assertCount(2, $contributions['values']);
546 $lines = $this->callAPISuccess('LineItem', 'get', ['sequential' => 1]);
547 $this->assertEquals(10, $lines['values'][0]['line_total']);
548 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', []);
549 $this->assertTrue(in_array($membershipPayment['contribution_id'], array_keys($contributions['values'])));
550 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $membershipPayment['membership_id']]);
551 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
552 }
553
554 /**
555 * Test submit with a membership block in place.
556 *
557 * @throws \CRM_Core_Exception
558 */
559 public function testSubmitMembershipBlockIsSeparatePaymentWithPayLater() {
560 $this->setUpMembershipContributionPage(TRUE);
561 $this->_ids['membership_type'] = [$this->membershipTypeCreate(['minimum_fee' => 2])];
562 //Pay later
563 $submitParams = [
564 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
565 'id' => (int) $this->_ids['contribution_page'],
566 'amount' => 0,
567 'billing_first_name' => 'Billy',
568 'billing_middle_name' => 'Goat',
569 'billing_last_name' => 'Gruff',
570 'is_pay_later' => 1,
571 'selectMembership' => $this->_ids['membership_type'],
572 ];
573
574 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
575 $contributions = $this->callAPISuccess('contribution', 'get', ['contribution_page_id' => $this->_ids['contribution_page']]);
576 $this->assertCount(2, $contributions['values']);
577 foreach ($contributions['values'] as $val) {
578 $this->assertEquals(CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending'), $val['contribution_status_id']);
579 }
580
581 //Membership should be in Pending state.
582 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', []);
583 $this->assertTrue(in_array($membershipPayment['contribution_id'], array_keys($contributions['values'])));
584 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $membershipPayment['membership_id']]);
585 $pendingStatus = $this->callAPISuccessGetSingle('MembershipStatus', [
586 'return' => ["id"],
587 'name' => "Pending",
588 ]);
589 $this->assertEquals($membership['status_id'], $pendingStatus['id']);
590 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
591 }
592
593 /**
594 * Test submit with a membership block in place.
595 *
596 * @throws \CRM_Core_Exception
597 */
598 public function testSubmitMembershipBlockIsSeparatePaymentWithEmail() {
599 $mut = new CiviMailUtils($this, TRUE);
600 $this->setUpMembershipContributionPage(TRUE);
601 $this->addProfile('supporter_profile', $this->_ids['contribution_page']);
602
603 $submitParams = [
604 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
605 'id' => (int) $this->_ids['contribution_page'],
606 'amount' => 10,
607 'billing_first_name' => 'Billy',
608 'billing_middle_name' => 'Goat',
609 'billing_last_name' => 'Gruff',
610 'selectMembership' => $this->_ids['membership_type'],
611 'email-Primary' => 'billy-goat@the-bridge.net',
612 'payment_processor_id' => $this->_paymentProcessor['id'],
613 'credit_card_number' => '4111111111111111',
614 'credit_card_type' => 'Visa',
615 'credit_card_exp_date' => ['M' => 9, 'Y' => 2040],
616 'cvv2' => 123,
617 ];
618
619 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
620 $contributions = $this->callAPISuccess('contribution', 'get', ['contribution_page_id' => $this->_ids['contribution_page']]);
621 $this->assertCount(2, $contributions['values']);
622 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', []);
623 $this->assertTrue(in_array($membershipPayment['contribution_id'], array_keys($contributions['values'])));
624 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $membershipPayment['membership_id']]);
625 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
626 // We should have two separate email messages, each with their own amount
627 // line and no total line.
628 $mut->checkAllMailLog(
629 [
630 'Amount: $ 2.00',
631 'Amount: $ 10.00',
632 'Membership Fee',
633 ],
634 [
635 'Total: $',
636 ]
637 );
638 $mut->stop();
639 $mut->clearMessages();
640 }
641
642 /**
643 * Test submit with a membership block in place.
644 *
645 * @throws \CRM_Core_Exception
646 */
647 public function testSubmitMembershipBlockIsSeparatePaymentZeroDollarsPayLaterWithEmail() {
648 $mut = new CiviMailUtils($this, TRUE);
649 $this->_ids['membership_type'] = [$this->membershipTypeCreate(['minimum_fee' => 0])];
650 $this->setUpMembershipContributionPage(TRUE);
651 $this->addProfile('supporter_profile', $this->_ids['contribution_page']);
652
653 $submitParams = [
654 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
655 'id' => (int) $this->_ids['contribution_page'],
656 'amount' => 0,
657 'billing_first_name' => 'Billy',
658 'billing_middle_name' => 'Goat',
659 'billing_last_name' => 'Gruffalo',
660 'selectMembership' => $this->_ids['membership_type'],
661 'payment_processor_id' => 0,
662 'email-Primary' => 'gruffalo@the-bridge.net',
663 ];
664
665 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL);
666 $contributions = $this->callAPISuccess('contribution', 'get', ['contribution_page_id' => $this->_ids['contribution_page']]);
667 $this->assertCount(2, $contributions['values']);
668 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', []);
669 $this->assertTrue(in_array($membershipPayment['contribution_id'], array_keys($contributions['values'])));
670 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $membershipPayment['membership_id']]);
671 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
672 $mut->checkMailLog([
673 'Gruffalo',
674 'General Membership: $ 0.00',
675 'Membership Fee',
676 ]);
677 $mut->stop();
678 $mut->clearMessages();
679 }
680
681 /**
682 * Test submit with a membership block in place.
683 *
684 * @throws \CRM_Core_Exception
685 */
686 public function testSubmitMembershipBlockTwoTypesIsSeparatePayment() {
687 $this->_ids['membership_type'] = [$this->membershipTypeCreate(['minimum_fee' => 6])];
688 $this->_ids['membership_type'][] = $this->membershipTypeCreate(['name' => 'Student', 'minimum_fee' => 50]);
689 $this->setUpMembershipContributionPage(TRUE);
690 $submitParams = [
691 'price_' . $this->_ids['price_field'][0] => $this->_ids['price_field_value'][1],
692 'id' => (int) $this->_ids['contribution_page'],
693 'amount' => 10,
694 'billing_first_name' => 'Billy',
695 'billing_middle_name' => 'Goat',
696 'billing_last_name' => 'Gruff',
697 'selectMembership' => $this->_ids['membership_type'][1],
698 ];
699
700 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL);
701 $contributions = $this->callAPISuccess('contribution', 'get', ['contribution_page_id' => $this->_ids['contribution_page']]);
702 $this->assertCount(2, $contributions['values']);
703 $ids = array_keys($contributions['values']);
704 $this->assertEquals('10.00', $contributions['values'][$ids[0]]['total_amount']);
705 $this->assertEquals('50.00', $contributions['values'][$ids[1]]['total_amount']);
706 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', []);
707 $this->assertArrayHasKey($membershipPayment['contribution_id'], $contributions['values']);
708 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $membershipPayment['membership_id']]);
709 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
710 }
711
712 /**
713 * Test submit with a membership block in place.
714 *
715 * We are expecting a separate payment for the membership vs the contribution.
716 *
717 * @throws \CRM_Core_Exception
718 * @throws \CiviCRM_API3_Exception
719 */
720 public function testSubmitMembershipBlockIsSeparatePaymentPaymentProcessorNow() {
721 $mut = new CiviMailUtils($this, TRUE);
722 $this->setUpMembershipContributionPage(TRUE);
723 $processor = Civi\Payment\System::singleton()->getById($this->_paymentProcessor['id']);
724 $processor->setDoDirectPaymentResult(['fee_amount' => .72]);
725 $submitParams = [
726 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
727 'id' => (int) $this->_ids['contribution_page'],
728 'amount' => 10,
729 'billing_first_name' => 'Billy',
730 'billing_middle_name' => 'Goat',
731 'billing_last_name' => 'Gruff',
732 'email-Primary' => 'henry@8th.king',
733 'selectMembership' => $this->_ids['membership_type'],
734 'payment_processor_id' => $this->_paymentProcessor['id'],
735 'credit_card_number' => '4111111111111111',
736 'credit_card_type' => 'Visa',
737 'credit_card_exp_date' => ['M' => 9, 'Y' => 2040],
738 'cvv2' => 123,
739 ];
740
741 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL);
742 $contributions = $this->callAPISuccess('contribution', 'get', [
743 'contribution_page_id' => $this->_ids['contribution_page'],
744 'contribution_status_id' => 1,
745 ]);
746 $this->assertCount(2, $contributions['values']);
747 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', []);
748 $this->assertTrue(in_array($membershipPayment['contribution_id'], array_keys($contributions['values'])));
749 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $membershipPayment['membership_id']]);
750 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
751 $lineItem = $this->callAPISuccessGetSingle('LineItem', ['entity_table' => 'civicrm_membership']);
752 $this->assertEquals($lineItem['entity_id'], $membership['id']);
753 $this->assertEquals($lineItem['contribution_id'], $membershipPayment['contribution_id']);
754 $this->assertEquals($lineItem['qty'], 1);
755 $this->assertEquals($lineItem['unit_price'], 2);
756 $this->assertEquals($lineItem['line_total'], 2);
757 foreach ($contributions['values'] as $contribution) {
758 $this->assertEquals(.72, $contribution['fee_amount']);
759 $this->assertEquals($contribution['total_amount'] - .72, $contribution['net_amount']);
760 }
761 // The total string is currently absent & it seems worse with - although at some point
762 // it may have been intended
763 $mut->checkAllMailLog(['$ 2.00', 'Contribution Amount', '$ 10.00'], ['Total:']);
764 $mut->stop();
765 $mut->clearMessages();
766 }
767
768 /**
769 * Test submit with a membership block in place.
770 *
771 * Ensure a separate payment for the membership vs the contribution, with
772 * correct amounts.
773 *
774 * @param string $thousandSeparator
775 * punctuation used to refer to thousands.
776 *
777 * @throws \CRM_Core_Exception
778 * @throws \CiviCRM_API3_Exception
779 *
780 * @dataProvider getThousandSeparators
781 */
782 public function testSubmitMembershipBlockIsSeparatePaymentPaymentProcessorNowChargesCorrectAmounts($thousandSeparator) {
783 $this->setCurrencySeparators($thousandSeparator);
784 $this->setUpMembershipContributionPage(TRUE);
785 $processor = Civi\Payment\System::singleton()->getById($this->_paymentProcessor['id']);
786 $processor->setDoDirectPaymentResult(['fee_amount' => .72]);
787 $test_uniq = uniqid();
788 $contributionPageAmount = 10;
789 $submitParams = [
790 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
791 'id' => (int) $this->_ids['contribution_page'],
792 'amount' => $contributionPageAmount,
793 'billing_first_name' => 'Billy',
794 'billing_middle_name' => 'Goat',
795 'billing_last_name' => 'Gruff',
796 'email-Primary' => 'henry@8th.king',
797 'selectMembership' => $this->_ids['membership_type'],
798 'payment_processor_id' => $this->_paymentProcessor['id'],
799 'credit_card_number' => '4111111111111111',
800 'credit_card_type' => 'Visa',
801 'credit_card_exp_date' => ['M' => 9, 'Y' => 2040],
802 'cvv2' => 123,
803 'TEST_UNIQ' => $test_uniq,
804 ];
805
806 // set custom hook
807 $this->hookClass->setHook('civicrm_alterPaymentProcessorParams', [$this, 'hook_civicrm_alterPaymentProcessorParams']);
808
809 $this->callAPISuccess('ContributionPage', 'submit', $submitParams);
810 $this->callAPISuccess('contribution', 'get', [
811 'contribution_page_id' => $this->_ids['contribution_page'],
812 'contribution_status_id' => 1,
813 ]);
814
815 $result = civicrm_api3('SystemLog', 'get', [
816 'sequential' => 1,
817 'message' => ['LIKE' => "%{$test_uniq}%"],
818 ]);
819 $this->assertCount(2, $result['values'], "Expected exactly 2 log entries matching {$test_uniq}.");
820
821 // Examine logged entries to ensure correct values.
822 $contribution_ids = [];
823 $found_membership_amount = $found_contribution_amount = FALSE;
824 foreach ($result['values'] as $value) {
825 list($junk, $json) = explode("$test_uniq:", $value['message']);
826 $logged_contribution = json_decode($json, TRUE);
827 $contribution_ids[] = $logged_contribution['contributionID'];
828 if (!empty($logged_contribution['total_amount'])) {
829 $amount = $logged_contribution['total_amount'];
830 }
831 else {
832 $amount = $logged_contribution['amount'];
833 }
834
835 if ($amount == $this->_membershipBlockAmount) {
836 $found_membership_amount = TRUE;
837 }
838 if ($amount == $contributionPageAmount) {
839 $found_contribution_amount = TRUE;
840 }
841 }
842
843 $distinct_contribution_ids = array_unique($contribution_ids);
844 $this->assertCount(2, $distinct_contribution_ids, "Expected exactly 2 log contributions with distinct contributionIDs.");
845 $this->assertTrue($found_contribution_amount, "Expected one log contribution with amount '$contributionPageAmount' (the contribution page amount)");
846 $this->assertTrue($found_membership_amount, "Expected one log contribution with amount '$this->_membershipBlockAmount' (the membership amount)");
847 }
848
849 /**
850 * Test that when a transaction fails the pending contribution remains.
851 *
852 * An activity should also be created. CRM-16417.
853 *
854 * @throws \CRM_Core_Exception
855 */
856 public function testSubmitPaymentProcessorFailure() {
857 $this->setUpContributionPage();
858 $this->setupPaymentProcessor();
859 $this->createLoggedInUser();
860 $priceFieldID = reset($this->_ids['price_field']);
861 $priceFieldValueID = reset($this->_ids['price_field_value']);
862 $submitParams = [
863 'price_' . $priceFieldID => $priceFieldValueID,
864 'id' => (int) $this->_ids['contribution_page'],
865 'amount' => 10,
866 'payment_processor_id' => 1,
867 'credit_card_number' => '4111111111111111',
868 'credit_card_type' => 'Visa',
869 'credit_card_exp_date' => ['M' => 9, 'Y' => 2008],
870 'cvv2' => 123,
871 ];
872
873 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
874 $contribution = $this->callAPISuccessGetSingle('contribution', [
875 'contribution_page_id' => $this->_ids['contribution_page'],
876 'contribution_status_id' => 'Failed',
877 ]);
878
879 $this->callAPISuccessGetSingle('activity', [
880 'source_record_id' => $contribution['id'],
881 'activity_type_id' => 'Failed Payment',
882 ]);
883
884 }
885
886 /**
887 * Test submit recurring (yearly) membership with immediate confirmation (IATS style).
888 *
889 * - we process 2 membership transactions against with a recurring contribution against a contribution page with an immediate
890 * processor (IATS style - denoted by returning trxn_id)
891 * - the first creates a new membership, completed contribution, in progress recurring. Check these
892 * - create another - end date should be extended
893 *
894 * @throws \CRM_Core_Exception
895 */
896 public function testSubmitMembershipPriceSetPaymentPaymentProcessorRecurInstantPaymentYear() {
897 $this->doSubmitMembershipPriceSetPaymentPaymentProcessorRecurInstantPayment(['duration_unit' => 'year', 'recur_frequency_unit' => 'year']);
898 }
899
900 /**
901 * Test submit recurring (monthly) membership with immediate confirmation (IATS style).
902 *
903 * - we process 2 membership transactions against with a recurring contribution against a contribution page with an immediate
904 * processor (IATS style - denoted by returning trxn_id)
905 * - the first creates a new membership, completed contribution, in progress recurring. Check these
906 * - create another - end date should be extended
907 */
908 public function testSubmitMembershipPriceSetPaymentPaymentProcessorRecurInstantPaymentMonth() {
909 $this->doSubmitMembershipPriceSetPaymentPaymentProcessorRecurInstantPayment(['duration_unit' => 'month', 'recur_frequency_unit' => 'month']);
910 }
911
912 /**
913 * Test submit recurring (mismatched frequency unit) membership with immediate confirmation (IATS style).
914 *
915 * - we process 2 membership transactions against with a recurring contribution against a contribution page with an immediate
916 * processor (IATS style - denoted by returning trxn_id)
917 * - the first creates a new membership, completed contribution, in progress recurring. Check these
918 * - create another - end date should be extended
919 */
920 //public function testSubmitMembershipPriceSetPaymentPaymentProcessorRecurInstantPaymentDifferentFrequency() {
921 // $this->doSubmitMembershipPriceSetPaymentPaymentProcessorRecurInstantPayment(array('duration_unit' => 'year', 'recur_frequency_unit' => 'month'));
922 //}
923
924 /**
925 * Helper function for testSubmitMembershipPriceSetPaymentProcessorRecurInstantPayment*
926 * @param array $params
927 *
928 * @throws \CRM_Core_Exception
929 */
930 public function doSubmitMembershipPriceSetPaymentPaymentProcessorRecurInstantPayment($params = []) {
931 $this->params['is_recur'] = 1;
932 $this->params['recur_frequency_unit'] = $params['recur_frequency_unit'];
933 $membershipTypeParams['duration_unit'] = $params['duration_unit'];
934 if ($params['recur_frequency_unit'] === $params['duration_unit']) {
935 $durationUnit = $params['duration_unit'];
936 }
937 else {
938 $durationUnit = NULL;
939 }
940 $this->setUpMembershipContributionPage(FALSE, FALSE, $membershipTypeParams);
941 $dummyPP = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
942 $dummyPP->setDoDirectPaymentResult(['payment_status_id' => 1, 'trxn_id' => 'create_first_success']);
943 $processor = $dummyPP->getPaymentProcessor();
944
945 if ($params['recur_frequency_unit'] === $params['duration_unit']) {
946 // Membership will be in "New" state because it will get confirmed as payment matches
947 $expectedMembershipStatus = 1;
948 }
949 else {
950 // Membership will still be in "Pending" state as it won't get confirmed as payment doesn't match
951 $expectedMembershipStatus = 5;
952 }
953
954 $submitParams = [
955 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
956 'id' => (int) $this->_ids['contribution_page'],
957 'amount' => 10,
958 'billing_first_name' => 'Billy',
959 'billing_middle_name' => 'Goat',
960 'billing_last_name' => 'Gruff',
961 'email' => 'billy@goat.gruff',
962 'selectMembership' => $this->_ids['membership_type'],
963 'payment_processor_id' => 1,
964 'credit_card_number' => '4111111111111111',
965 'credit_card_type' => 'Visa',
966 'credit_card_exp_date' => ['M' => 9, 'Y' => 2040],
967 'cvv2' => 123,
968 'is_recur' => 1,
969 'frequency_interval' => 1,
970 'frequency_unit' => $this->params['recur_frequency_unit'],
971 ];
972
973 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL);
974 $contribution = $this->callAPISuccess('contribution', 'getsingle', [
975 'contribution_page_id' => $this->_ids['contribution_page'],
976 'contribution_status_id' => 1,
977 ]);
978 $this->assertEquals($processor['payment_instrument_id'], $contribution['payment_instrument_id']);
979
980 $this->assertEquals('create_first_success', $contribution['trxn_id']);
981 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', []);
982 $this->assertEquals($membershipPayment['contribution_id'], $contribution['id']);
983 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $membershipPayment['membership_id']]);
984 $this->assertEquals($membership['contact_id'], $contribution['contact_id']);
985 $this->assertEquals($expectedMembershipStatus, $membership['status_id']);
986 $this->callAPISuccess('contribution_recur', 'getsingle', ['id' => $contribution['contribution_recur_id']]);
987 $this->assertEquals($contribution['contribution_recur_id'], $membership['contribution_recur_id']);
988
989 $this->callAPISuccess('line_item', 'getsingle', ['contribution_id' => $contribution['id'], 'entity_id' => $membership['id']]);
990 //renew it with processor setting completed - should extend membership
991 $submitParams['contact_id'] = $contribution['contact_id'];
992 $dummyPP->setDoDirectPaymentResult(['payment_status_id' => 1, 'trxn_id' => 'create_second_success']);
993 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
994 $this->callAPISuccess('contribution', 'getsingle', [
995 'id' => ['NOT IN' => [$contribution['id']]],
996 'contribution_page_id' => $this->_ids['contribution_page'],
997 'contribution_status_id' => 1,
998 ]);
999 $renewedMembership = $this->callAPISuccessGetSingle('membership', ['id' => $membershipPayment['membership_id']]);
1000 if ($durationUnit) {
1001 // We only have an end_date if frequency units match, otherwise membership won't be autorenewed and dates won't be calculated.
1002 $renewedMembershipEndDate = $this->membershipRenewalDate($durationUnit, $membership['end_date']);
1003 $this->assertEquals($renewedMembershipEndDate, $renewedMembership['end_date']);
1004 }
1005 $recurringContribution = $this->callAPISuccess('contribution_recur', 'getsingle', ['id' => $contribution['contribution_recur_id']]);
1006 $this->assertEquals($processor['payment_instrument_id'], $recurringContribution['payment_instrument_id']);
1007 $this->assertEquals(5, $recurringContribution['contribution_status_id']);
1008 }
1009
1010 /**
1011 * Test submit recurring membership with immediate confirmation (IATS style).
1012 *
1013 * - we process 2 membership transactions against with a recurring contribution against a contribution page with an immediate
1014 * processor (IATS style - denoted by returning trxn_id)
1015 * - the first creates a new membership, completed contribution, in progress recurring. Check these
1016 * - create another - end date should be extended
1017 *
1018 * @throws \CRM_Core_Exception
1019 */
1020 public function testSubmitMembershipComplexNonPriceSetPaymentPaymentProcessorRecurInstantPayment() {
1021 $this->params['is_recur'] = 1;
1022 $this->params['recur_frequency_unit'] = $membershipTypeParams['duration_unit'] = 'year';
1023 // Add a membership so membership & contribution are not both 1.
1024 $preExistingMembershipID = $this->contactMembershipCreate(['contact_id' => $this->contactIds[0]]);
1025 $this->setUpMembershipContributionPage(FALSE, FALSE, $membershipTypeParams);
1026 $dummyPP = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
1027 $dummyPP->setDoDirectPaymentResult(['payment_status_id' => 1, 'trxn_id' => 'create_first_success']);
1028 $processor = $dummyPP->getPaymentProcessor();
1029
1030 $submitParams = [
1031 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
1032 'price_' . $this->_ids['price_field']['cont'] => 88,
1033 'id' => (int) $this->_ids['contribution_page'],
1034 'amount' => 10,
1035 'billing_first_name' => 'Billy',
1036 'billing_middle_name' => 'Goat',
1037 'billing_last_name' => 'Gruff',
1038 'email' => 'billy@goat.gruff',
1039 'selectMembership' => $this->_ids['membership_type'],
1040 'payment_processor_id' => 1,
1041 'credit_card_number' => '4111111111111111',
1042 'credit_card_type' => 'Visa',
1043 'credit_card_exp_date' => ['M' => 9, 'Y' => 2040],
1044 'cvv2' => 123,
1045 'is_recur' => 1,
1046 'frequency_interval' => 1,
1047 'frequency_unit' => $this->params['recur_frequency_unit'],
1048 ];
1049
1050 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL);
1051 $contribution = $this->callAPISuccess('contribution', 'getsingle', [
1052 'contribution_page_id' => $this->_ids['contribution_page'],
1053 'contribution_status_id' => 1,
1054 ]);
1055 $this->assertEquals($processor['payment_instrument_id'], $contribution['payment_instrument_id']);
1056
1057 $this->assertEquals('create_first_success', $contribution['trxn_id']);
1058 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', []);
1059 $this->assertEquals($membershipPayment['contribution_id'], $contribution['id']);
1060 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $membershipPayment['membership_id']]);
1061 $this->assertEquals($membership['contact_id'], $contribution['contact_id']);
1062 $this->assertEquals(1, $membership['status_id']);
1063 $this->callAPISuccess('contribution_recur', 'getsingle', ['id' => $contribution['contribution_recur_id']]);
1064
1065 $lines = $this->callAPISuccess('line_item', 'get', ['sequential' => 1, 'contribution_id' => $contribution['id']]);
1066 $this->assertEquals(2, $lines['count']);
1067 $this->assertEquals('civicrm_membership', $lines['values'][0]['entity_table']);
1068 $this->assertEquals($preExistingMembershipID + 1, $lines['values'][0]['entity_id']);
1069 $this->assertEquals('civicrm_contribution', $lines['values'][1]['entity_table']);
1070 $this->assertEquals($contribution['id'], $lines['values'][1]['entity_id']);
1071 $this->callAPISuccessGetSingle('MembershipPayment', ['contribution_id' => $contribution['id'], 'membership_id' => $preExistingMembershipID + 1]);
1072
1073 //renew it with processor setting completed - should extend membership
1074 $submitParams['contact_id'] = $contribution['contact_id'];
1075 $dummyPP->setDoDirectPaymentResult(['payment_status_id' => 1, 'trxn_id' => 'create_second_success']);
1076 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
1077 $renewContribution = $this->callAPISuccess('contribution', 'getsingle', [
1078 'id' => ['NOT IN' => [$contribution['id']]],
1079 'contribution_page_id' => $this->_ids['contribution_page'],
1080 'contribution_status_id' => 1,
1081 ]);
1082 $lines = $this->callAPISuccess('line_item', 'get', ['sequential' => 1, 'contribution_id' => $renewContribution['id']]);
1083 $this->assertEquals(2, $lines['count']);
1084 $this->assertEquals('civicrm_membership', $lines['values'][0]['entity_table']);
1085 $this->assertEquals($preExistingMembershipID + 1, $lines['values'][0]['entity_id']);
1086 $this->assertEquals('civicrm_contribution', $lines['values'][1]['entity_table']);
1087 $this->assertEquals($renewContribution['id'], $lines['values'][1]['entity_id']);
1088
1089 $renewedMembership = $this->callAPISuccessGetSingle('membership', ['id' => $membershipPayment['membership_id']]);
1090 $this->assertEquals(date('Y-m-d', strtotime('+ 1 ' . $this->params['recur_frequency_unit'], strtotime($membership['end_date']))), $renewedMembership['end_date']);
1091 $recurringContribution = $this->callAPISuccess('contribution_recur', 'getsingle', ['id' => $contribution['contribution_recur_id']]);
1092 $this->assertEquals($processor['payment_instrument_id'], $recurringContribution['payment_instrument_id']);
1093 $this->assertEquals(5, $recurringContribution['contribution_status_id']);
1094 }
1095
1096 /**
1097 * Test submit recurring membership with immediate confirmation (IATS style).
1098 *
1099 * - we process 2 membership transactions against with a recurring contribution against a contribution page with an immediate
1100 * processor (IATS style - denoted by returning trxn_id)
1101 * - the first creates a new membership, completed contribution, in progress recurring. Check these
1102 * - create another - end date should be extended
1103 *
1104 * @throws \CRM_Core_Exception
1105 */
1106 public function testSubmitMembershipComplexPriceSetPaymentPaymentProcessorRecurInstantPayment() {
1107 $this->params['is_recur'] = 1;
1108 $this->params['recur_frequency_unit'] = $membershipTypeParams['duration_unit'] = 'year';
1109 // Add a membership so membership & contribution are not both 1.
1110 $preExistingMembershipID = $this->contactMembershipCreate(['contact_id' => $this->contactIds[0]]);
1111 $this->createPriceSetWithPage();
1112 $this->addSecondOrganizationMembershipToPriceSet();
1113 $this->setupPaymentProcessor();
1114
1115 $dummyPP = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
1116 $dummyPP->setDoDirectPaymentResult(['payment_status_id' => 1, 'trxn_id' => 'create_first_success']);
1117 $processor = $dummyPP->getPaymentProcessor();
1118
1119 $submitParams = [
1120 'price_' . $this->_ids['price_field'][0] => $this->_ids['price_field_value']['cont'],
1121 'price_' . $this->_ids['price_field']['org1'] => $this->_ids['price_field_value']['org1'],
1122 'price_' . $this->_ids['price_field']['org2'] => $this->_ids['price_field_value']['org2'],
1123 'id' => (int) $this->_ids['contribution_page'],
1124 'amount' => 10,
1125 'billing_first_name' => 'Billy',
1126 'billing_middle_name' => 'Goat',
1127 'billing_last_name' => 'Gruff',
1128 'email' => 'billy@goat.gruff',
1129 'selectMembership' => NULL,
1130 'payment_processor_id' => 1,
1131 'credit_card_number' => '4111111111111111',
1132 'credit_card_type' => 'Visa',
1133 'credit_card_exp_date' => ['M' => 9, 'Y' => 2040],
1134 'cvv2' => 123,
1135 'frequency_interval' => 1,
1136 'frequency_unit' => $this->params['recur_frequency_unit'],
1137 ];
1138
1139 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL);
1140 $contribution = $this->callAPISuccess('contribution', 'getsingle', [
1141 'contribution_page_id' => $this->_ids['contribution_page'],
1142 'contribution_status_id' => 1,
1143 ]);
1144 $this->assertEquals($processor['payment_instrument_id'], $contribution['payment_instrument_id']);
1145
1146 $this->assertEquals('create_first_success', $contribution['trxn_id']);
1147 $membershipPayments = $this->callAPISuccess('membership_payment', 'get', [
1148 'sequential' => 1,
1149 'contribution_id' => $contribution['id'],
1150 ]);
1151 $this->assertEquals(2, $membershipPayments['count']);
1152 $lines = $this->callAPISuccess('line_item', 'get', ['sequential' => 1, 'contribution_id' => $contribution['id']]);
1153 $this->assertEquals(3, $lines['count']);
1154 $this->assertEquals('civicrm_membership', $lines['values'][0]['entity_table']);
1155 $this->assertEquals($preExistingMembershipID + 1, $lines['values'][0]['entity_id']);
1156 $this->assertEquals('civicrm_contribution', $lines['values'][1]['entity_table']);
1157 $this->assertEquals($contribution['id'], $lines['values'][1]['entity_id']);
1158 $this->assertEquals('civicrm_membership', $lines['values'][2]['entity_table']);
1159 $this->assertEquals($preExistingMembershipID + 2, $lines['values'][2]['entity_id']);
1160
1161 $this->callAPISuccessGetSingle('MembershipPayment', ['contribution_id' => $contribution['id'], 'membership_id' => $preExistingMembershipID + 1]);
1162 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $preExistingMembershipID + 1]);
1163
1164 //renew it with processor setting completed - should extend membership
1165 $submitParams['contact_id'] = $contribution['contact_id'];
1166 $dummyPP->setDoDirectPaymentResult(['payment_status_id' => 1, 'trxn_id' => 'create_second_success']);
1167 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
1168 $renewContribution = $this->callAPISuccess('contribution', 'getsingle', [
1169 'id' => ['NOT IN' => [$contribution['id']]],
1170 'contribution_page_id' => $this->_ids['contribution_page'],
1171 'contribution_status_id' => 1,
1172 ]);
1173 $lines = $this->callAPISuccess('line_item', 'get', ['sequential' => 1, 'contribution_id' => $renewContribution['id']]);
1174 $this->assertEquals(3, $lines['count']);
1175 $this->assertEquals('civicrm_membership', $lines['values'][0]['entity_table']);
1176 $this->assertEquals($preExistingMembershipID + 1, $lines['values'][0]['entity_id']);
1177 $this->assertEquals('civicrm_contribution', $lines['values'][1]['entity_table']);
1178 $this->assertEquals($renewContribution['id'], $lines['values'][1]['entity_id']);
1179
1180 $renewedMembership = $this->callAPISuccessGetSingle('membership', ['id' => $preExistingMembershipID + 1]);
1181 $this->assertEquals(date('Y-m-d', strtotime('+ 1 ' . $this->params['recur_frequency_unit'], strtotime($membership['end_date']))), $renewedMembership['end_date']);
1182 }
1183
1184 /**
1185 * Extend the price set with a second organisation's membership.
1186 *
1187 * @throws \CRM_Core_Exception
1188 */
1189 public function addSecondOrganizationMembershipToPriceSet() {
1190 $organization2ID = $this->organizationCreate();
1191 $membershipTypes = $this->callAPISuccess('MembershipType', 'get', []);
1192 $this->_ids['membership_type'] = array_keys($membershipTypes['values']);
1193 $this->_ids['membership_type']['org2'] = $this->membershipTypeCreate(['contact_id' => $organization2ID, 'name' => 'Org 2']);
1194 $priceField = $this->callAPISuccess('PriceField', 'create', [
1195 'price_set_id' => $this->_ids['price_set'],
1196 'html_type' => 'Radio',
1197 'name' => 'Org1 Price',
1198 'label' => 'Org1Price',
1199 ]);
1200 $this->_ids['price_field']['org1'] = $priceField['id'];
1201
1202 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', [
1203 'name' => 'org1 amount',
1204 'label' => 'org 1 Amount',
1205 'amount' => 2,
1206 'financial_type_id' => 'Member Dues',
1207 'format.only_id' => TRUE,
1208 'membership_type_id' => reset($this->_ids['membership_type']),
1209 'price_field_id' => $priceField['id'],
1210 ]);
1211 $this->_ids['price_field_value']['org1'] = $priceFieldValue;
1212
1213 $priceField = $this->callAPISuccess('PriceField', 'create', [
1214 'price_set_id' => $this->_ids['price_set'],
1215 'html_type' => 'Radio',
1216 'name' => 'Org2 Price',
1217 'label' => 'Org2Price',
1218 ]);
1219 $this->_ids['price_field']['org2'] = $priceField['id'];
1220
1221 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', [
1222 'name' => 'org2 amount',
1223 'label' => 'org 2 Amount',
1224 'amount' => 200,
1225 'financial_type_id' => 'Member Dues',
1226 'format.only_id' => TRUE,
1227 'membership_type_id' => $this->_ids['membership_type']['org2'],
1228 'price_field_id' => $priceField['id'],
1229 ]);
1230 $this->_ids['price_field_value']['org2'] = $priceFieldValue;
1231
1232 }
1233
1234 /**
1235 * Test submit recurring membership with immediate confirmation (IATS style).
1236 *
1237 * - we process 2 membership transactions against with a recurring contribution against a contribution page with an immediate
1238 * processor (IATS style - denoted by returning trxn_id)
1239 * - the first creates a new membership, completed contribution, in progress recurring. Check these
1240 * - create another - end date should be extended
1241 *
1242 * @throws \CRM_Core_Exception
1243 */
1244 public function testSubmitMembershipPriceSetPaymentPaymentProcessorSeparatePaymentRecurInstantPayment() {
1245
1246 $this->setUpMembershipContributionPage(TRUE);
1247 $dummyPP = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
1248 $dummyPP->setDoDirectPaymentResult(['payment_status_id' => 1, 'trxn_id' => 'create_first_success']);
1249
1250 $submitParams = [
1251 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
1252 'id' => (int) $this->_ids['contribution_page'],
1253 'amount' => 10,
1254 'billing_first_name' => 'Billy',
1255 'billing_middle_name' => 'Goat',
1256 'billing_last_name' => 'Gruff',
1257 'email' => 'billy@goat.gruff',
1258 'selectMembership' => $this->_ids['membership_type'][0],
1259 'payment_processor_id' => 1,
1260 'credit_card_number' => '4111111111111111',
1261 'credit_card_type' => 'Visa',
1262 'credit_card_exp_date' => ['M' => 9, 'Y' => 2040],
1263 'cvv2' => 123,
1264 'is_recur' => 1,
1265 'auto_renew' => TRUE,
1266 'frequency_interval' => 1,
1267 'frequency_unit' => 'month',
1268 ];
1269
1270 $this->callAPIAndDocument('ContributionPage', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL);
1271 $contribution = $this->callAPISuccess('contribution', 'get', [
1272 'contribution_page_id' => $this->_ids['contribution_page'],
1273 'contribution_status_id' => 1,
1274 ]);
1275
1276 $this->assertEquals(2, $contribution['count']);
1277 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', []);
1278 $this->callAPISuccessGetSingle('membership', ['id' => $membershipPayment['membership_id']]);
1279 $this->assertNotEmpty($contribution['values'][$membershipPayment['contribution_id']]['contribution_recur_id']);
1280 $this->callAPISuccess('contribution_recur', 'getsingle', []);
1281 }
1282
1283 /**
1284 * Test submit recurring membership with delayed confirmation (Authorize.net style)
1285 * - we process 2 membership transactions against with a recurring contribution against a contribution page with a delayed
1286 * processor (Authorize.net style - denoted by NOT returning trxn_id)
1287 * - the first creates a pending membership, pending contribution, penging recurring. Check these
1288 * - complete the transaction
1289 * - create another - end date should NOT be extended
1290 *
1291 * @throws \CRM_Core_Exception
1292 */
1293 public function testSubmitMembershipPriceSetPaymentPaymentProcessorRecurDelayed() {
1294 $this->params['is_recur'] = 1;
1295 $this->params['recur_frequency_unit'] = $membershipTypeParams['duration_unit'] = 'year';
1296 $this->setUpMembershipContributionPage();
1297 $dummyPP = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
1298 $dummyPP->setDoDirectPaymentResult(['payment_status_id' => 2]);
1299 $this->membershipTypeCreate(['name' => 'Student']);
1300
1301 // Add a contribution & a couple of memberships so the id will not be 1 & will differ from membership id.
1302 // This saves us from 'accidental success'.
1303 $this->contributionCreate(['contact_id' => $this->contactIds[0]]);
1304 $this->contactMembershipCreate(['contact_id' => $this->contactIds[0]]);
1305 $this->contactMembershipCreate(['contact_id' => $this->contactIds[0], 'membership_type_id' => 'Student']);
1306
1307 $submitParams = [
1308 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
1309 'id' => (int) $this->_ids['contribution_page'],
1310 'amount' => 10,
1311 'billing_first_name' => 'Billy',
1312 'billing_middle_name' => 'Goat',
1313 'billing_last_name' => 'Gruff',
1314 'email' => 'billy@goat.gruff',
1315 'selectMembership' => $this->_ids['membership_type'][0],
1316 'payment_processor_id' => 1,
1317 'credit_card_number' => '4111111111111111',
1318 'credit_card_type' => 'Visa',
1319 'credit_card_exp_date' => ['M' => 9, 'Y' => 2040],
1320 'cvv2' => 123,
1321 'is_recur' => 1,
1322 'frequency_interval' => 1,
1323 'frequency_unit' => $this->params['recur_frequency_unit'],
1324 ];
1325
1326 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL);
1327 $contribution = $this->callAPISuccess('contribution', 'getsingle', [
1328 'contribution_page_id' => $this->_ids['contribution_page'],
1329 'contribution_status_id' => 2,
1330 ]);
1331
1332 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', []);
1333 $this->assertEquals($membershipPayment['contribution_id'], $contribution['id']);
1334 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $membershipPayment['membership_id']]);
1335 $this->assertEquals($membership['contact_id'], $contribution['contact_id']);
1336 $this->assertEquals(5, $membership['status_id']);
1337
1338 $line = $this->callAPISuccess('line_item', 'getsingle', ['contribution_id' => $contribution['id']]);
1339 $this->assertEquals('civicrm_membership', $line['entity_table']);
1340 $this->assertEquals($membership['id'], $line['entity_id']);
1341
1342 $this->callAPISuccess('contribution', 'completetransaction', [
1343 'id' => $contribution['id'],
1344 'trxn_id' => 'ipn_called',
1345 'payment_processor_id' => $this->_paymentProcessor['id'],
1346 ]);
1347 $line = $this->callAPISuccess('line_item', 'getsingle', ['contribution_id' => $contribution['id']]);
1348 $this->assertEquals('civicrm_membership', $line['entity_table']);
1349 $this->assertEquals($membership['id'], $line['entity_id']);
1350
1351 $membership = $this->callAPISuccessGetSingle('membership', ['id' => $membershipPayment['membership_id']]);
1352 //renew it with processor setting completed - should extend membership
1353 $submitParams = array_merge($submitParams, [
1354 'contact_id' => $contribution['contact_id'],
1355 'is_recur' => 1,
1356 'frequency_interval' => 1,
1357 'frequency_unit' => $this->params['recur_frequency_unit'],
1358 ]);
1359
1360 $dummyPP->setDoDirectPaymentResult(['payment_status_id' => 2]);
1361 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
1362 $newContribution = $this->callAPISuccess('contribution', 'getsingle', [
1363 'id' => [
1364 'NOT IN' => [$contribution['id']],
1365 ],
1366 'contribution_page_id' => $this->_ids['contribution_page'],
1367 'contribution_status_id' => 2,
1368 ]);
1369 $line = $this->callAPISuccess('line_item', 'getsingle', ['contribution_id' => $newContribution['id']]);
1370 $this->assertEquals('civicrm_membership', $line['entity_table']);
1371 $this->assertEquals($membership['id'], $line['entity_id']);
1372
1373 $renewedMembership = $this->callAPISuccessGetSingle('membership', ['id' => $membershipPayment['membership_id']]);
1374 //no renewal as the date hasn't changed
1375 $this->assertEquals($membership['end_date'], $renewedMembership['end_date']);
1376 $recurringContribution = $this->callAPISuccess('contribution_recur', 'getsingle', ['id' => $newContribution['contribution_recur_id']]);
1377 $this->assertEquals(2, $recurringContribution['contribution_status_id']);
1378 }
1379
1380 /**
1381 * Test non-recur contribution with membership payment
1382 *
1383 * @throws \CRM_Core_Exception
1384 */
1385 public function testSubmitMembershipIsSeparatePaymentNotRecur() {
1386 //Create recur contribution page.
1387 $this->setUpMembershipContributionPage(TRUE, TRUE);
1388 $dummyPP = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
1389 $dummyPP->setDoDirectPaymentResult(['payment_status_id' => 1, 'trxn_id' => 'create_first_success']);
1390
1391 //Sumbit payment with recur disabled.
1392 $submitParams = [
1393 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
1394 'id' => (int) $this->_ids['contribution_page'],
1395 'amount' => 10,
1396 'frequency_interval' => 1,
1397 'frequency_unit' => 'month',
1398 'billing_first_name' => 'Billy',
1399 'billing_middle_name' => 'Goat',
1400 'billing_last_name' => 'Gruff',
1401 'email' => 'billy@goat.gruff',
1402 'selectMembership' => $this->_ids['membership_type'][0],
1403 'payment_processor_id' => 1,
1404 'credit_card_number' => '4111111111111111',
1405 'credit_card_type' => 'Visa',
1406 'credit_card_exp_date' => ['M' => 9, 'Y' => 2040],
1407 'cvv2' => 123,
1408 ];
1409
1410 //Assert if recur contribution is created.
1411 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
1412 $recur = $this->callAPISuccess('contribution_recur', 'get', []);
1413 $this->assertEmpty($recur['count']);
1414 }
1415
1416 /**
1417 * Set up membership contribution page.
1418 *
1419 * @param bool $isSeparatePayment
1420 * @param bool $isRecur
1421 * @param array $membershipTypeParams Parameters to pass to membershiptype.create API
1422 *
1423 * @throws \CRM_Core_Exception
1424 */
1425 public function setUpMembershipContributionPage($isSeparatePayment = FALSE, $isRecur = FALSE, $membershipTypeParams = []) {
1426 $this->setUpMembershipBlockPriceSet($membershipTypeParams);
1427 $this->setupPaymentProcessor();
1428 $this->setUpContributionPage($isRecur);
1429
1430 $this->callAPISuccess('membership_block', 'create', [
1431 'entity_id' => $this->_ids['contribution_page'],
1432 'entity_table' => 'civicrm_contribution_page',
1433 'is_required' => TRUE,
1434 'is_active' => TRUE,
1435 'is_separate_payment' => $isSeparatePayment,
1436 'membership_type_default' => $this->_ids['membership_type'],
1437 ]);
1438 }
1439
1440 /**
1441 * Set up pledge block.
1442 */
1443 public function setUpPledgeBlock() {
1444 $params = [
1445 'entity_table' => 'civicrm_contribution_page',
1446 'entity_id' => $this->_ids['contribution_page'],
1447 'pledge_frequency_unit' => 'week',
1448 'is_pledge_interval' => 0,
1449 'pledge_start_date' => json_encode(['calendar_date' => date('Ymd', strtotime("+1 month"))]),
1450 ];
1451 $pledgeBlock = CRM_Pledge_BAO_PledgeBlock::create($params);
1452 $this->_ids['pledge_block_id'] = $pledgeBlock->id;
1453 }
1454
1455 /**
1456 * The default data set does not include a complete default membership price set - not quite sure why.
1457 *
1458 * This function ensures it exists & populates $this->_ids with it's data
1459 *
1460 * @throws \CRM_Core_Exception
1461 */
1462 public function setUpMembershipBlockPriceSet($membershipTypeParams = []) {
1463 $this->_ids['price_set'][] = $this->callAPISuccess('price_set', 'getvalue', [
1464 'name' => 'default_membership_type_amount',
1465 'return' => 'id',
1466 ]);
1467 if (empty($this->_ids['membership_type'])) {
1468 $membershipTypeParams = array_merge([
1469 'minimum_fee' => 2,
1470 ], $membershipTypeParams);
1471 $this->_ids['membership_type'] = [$this->membershipTypeCreate($membershipTypeParams)];
1472 }
1473 $priceField = $this->callAPISuccess('price_field', 'create', [
1474 'price_set_id' => reset($this->_ids['price_set']),
1475 'name' => 'membership_amount',
1476 'label' => 'Membership Amount',
1477 'html_type' => 'Radio',
1478 'sequential' => 1,
1479 ]);
1480 $this->_ids['price_field'][] = $priceField['id'];
1481
1482 foreach ($this->_ids['membership_type'] as $membershipTypeID) {
1483 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', [
1484 'name' => 'membership_amount',
1485 'label' => 'Membership Amount',
1486 'amount' => $this->_membershipBlockAmount,
1487 'financial_type_id' => 'Donation',
1488 'format.only_id' => TRUE,
1489 'membership_type_id' => $membershipTypeID,
1490 'price_field_id' => $priceField['id'],
1491 ]);
1492 $this->_ids['price_field_value'][] = $priceFieldValue;
1493 }
1494 if (!empty($this->_ids['membership_type']['org2'])) {
1495 $priceField = $this->callAPISuccess('price_field', 'create', [
1496 'price_set_id' => reset($this->_ids['price_set']),
1497 'name' => 'membership_org2',
1498 'label' => 'Membership Org2',
1499 'html_type' => 'Checkbox',
1500 'sequential' => 1,
1501 ]);
1502 $this->_ids['price_field']['org2'] = $priceField['id'];
1503
1504 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', [
1505 'name' => 'membership_org2',
1506 'label' => 'Membership org 2',
1507 'amount' => 55,
1508 'financial_type_id' => 'Member Dues',
1509 'format.only_id' => TRUE,
1510 'membership_type_id' => $this->_ids['membership_type']['org2'],
1511 'price_field_id' => $priceField['id'],
1512 ]);
1513 $this->_ids['price_field_value']['org2'] = $priceFieldValue;
1514 }
1515 $priceField = $this->callAPISuccess('price_field', 'create', [
1516 'price_set_id' => reset($this->_ids['price_set']),
1517 'name' => 'Contribution',
1518 'label' => 'Contribution',
1519 'html_type' => 'Text',
1520 'sequential' => 1,
1521 'is_enter_qty' => 1,
1522 ]);
1523 $this->_ids['price_field']['cont'] = $priceField['id'];
1524 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', [
1525 'name' => 'contribution',
1526 'label' => 'Give me money',
1527 'amount' => 88,
1528 'financial_type_id' => 'Donation',
1529 'format.only_id' => TRUE,
1530 'price_field_id' => $priceField['id'],
1531 ]);
1532 $this->_ids['price_field_value'][] = $priceFieldValue;
1533 }
1534
1535 /**
1536 * Add text field other amount to the price set.
1537 *
1538 * @throws \CRM_Core_Exception
1539 */
1540 public function addOtherAmountFieldToMembershipPriceSet() {
1541 $this->_ids['price_field']['other_amount'] = $this->callAPISuccess('price_field', 'create', [
1542 'price_set_id' => reset($this->_ids['price_set']),
1543 'name' => 'other_amount',
1544 'label' => 'Other Amount',
1545 'html_type' => 'Text',
1546 'format.only_id' => TRUE,
1547 'sequential' => 1,
1548 ]);
1549 $this->_ids['price_field_value']['other_amount'] = $this->callAPISuccess('price_field_value', 'create', [
1550 'financial_type_id' => 'Donation',
1551 'format.only_id' => TRUE,
1552 'label' => 'Other Amount',
1553 'amount' => 1,
1554 'price_field_id' => $this->_ids['price_field']['other_amount'],
1555 ]);
1556 }
1557
1558 /**
1559 * Help function to set up contribution page with some defaults.
1560 *
1561 * @param bool $isRecur
1562 *
1563 * @throws \CRM_Core_Exception
1564 */
1565 public function setUpContributionPage($isRecur = FALSE) {
1566 if ($isRecur) {
1567 $this->params['is_recur'] = 1;
1568 $this->params['recur_frequency_unit'] = 'month';
1569 }
1570 $this->params['frontend_title'] = 'Test Frontend title';
1571 $contributionPageResult = $this->callAPISuccess($this->_entity, 'create', $this->params);
1572 if (empty($this->_ids['price_set'])) {
1573 $priceSet = $this->callAPISuccess('price_set', 'create', $this->_priceSetParams);
1574 $this->_ids['price_set'][] = $priceSet['id'];
1575 }
1576 $priceSetID = reset($this->_ids['price_set']);
1577 CRM_Price_BAO_PriceSet::addTo('civicrm_contribution_page', $contributionPageResult['id'], $priceSetID);
1578
1579 if (empty($this->_ids['price_field'])) {
1580 $priceField = $this->callAPISuccess('price_field', 'create', [
1581 'price_set_id' => $priceSetID,
1582 'label' => 'Goat Breed',
1583 'html_type' => 'Radio',
1584 ]);
1585 $this->_ids['price_field'] = [$priceField['id']];
1586 }
1587 if (empty($this->_ids['price_field_value'])) {
1588 $this->callAPISuccess('price_field_value', 'create', [
1589 'price_set_id' => $priceSetID,
1590 'price_field_id' => $priceField['id'],
1591 'label' => 'Long Haired Goat',
1592 'financial_type_id' => 'Donation',
1593 'amount' => 20,
1594 'non_deductible_amount' => 15,
1595 ]);
1596 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', [
1597 'price_set_id' => $priceSetID,
1598 'price_field_id' => $priceField['id'],
1599 'label' => 'Shoe-eating Goat',
1600 'financial_type_id' => 'Donation',
1601 'amount' => 10,
1602 'non_deductible_amount' => 5,
1603 ]);
1604 $this->_ids['price_field_value'] = [$priceFieldValue['id']];
1605
1606 $this->_ids['price_field_value']['cheapskate'] = $this->callAPISuccess('price_field_value', 'create', [
1607 'price_set_id' => $priceSetID,
1608 'price_field_id' => $priceField['id'],
1609 'label' => 'Stingy Goat',
1610 'financial_type_id' => 'Donation',
1611 'amount' => 0,
1612 'non_deductible_amount' => 0,
1613 ])['id'];
1614 }
1615 $this->_ids['contribution_page'] = $contributionPageResult['id'];
1616 }
1617
1618 /**
1619 * Helper function to set up contribution page which can be used to purchase a
1620 * membership type for different intervals.
1621 *
1622 * @throws \CRM_Core_Exception
1623 */
1624 public function setUpMultiIntervalMembershipContributionPage() {
1625 $this->setupPaymentProcessor();
1626 $contributionPage = $this->callAPISuccess($this->_entity, 'create', $this->params);
1627 $this->_ids['contribution_page'] = $contributionPage['id'];
1628
1629 $this->_ids['membership_type'] = $this->membershipTypeCreate([
1630 // force auto-renew
1631 'auto_renew' => 2,
1632 'duration_unit' => 'month',
1633 ]);
1634
1635 $priceSet = $this->callAPISuccess('PriceSet', 'create', [
1636 'is_quick_config' => 0,
1637 'extends' => 'CiviMember',
1638 'financial_type_id' => 'Member Dues',
1639 'title' => 'CRM-21177',
1640 ]);
1641 $this->_ids['price_set'] = $priceSet['id'];
1642
1643 $priceField = $this->callAPISuccess('price_field', 'create', [
1644 'price_set_id' => $this->_ids['price_set'],
1645 'name' => 'membership_type',
1646 'label' => 'Membership Type',
1647 'html_type' => 'Radio',
1648 ]);
1649 $this->_ids['price_field'] = $priceField['id'];
1650
1651 $priceFieldValueMonthly = $this->callAPISuccess('price_field_value', 'create', [
1652 'name' => 'CRM-21177_Monthly',
1653 'label' => 'CRM-21177 - Monthly',
1654 'amount' => 20,
1655 'membership_num_terms' => 1,
1656 'membership_type_id' => $this->_ids['membership_type'],
1657 'price_field_id' => $this->_ids['price_field'],
1658 'financial_type_id' => 'Member Dues',
1659 ]);
1660 $this->_ids['price_field_value_monthly'] = $priceFieldValueMonthly['id'];
1661
1662 $priceFieldValueYearly = $this->callAPISuccess('price_field_value', 'create', [
1663 'name' => 'CRM-21177_Yearly',
1664 'label' => 'CRM-21177 - Yearly',
1665 'amount' => 200,
1666 'membership_num_terms' => 12,
1667 'membership_type_id' => $this->_ids['membership_type'],
1668 'price_field_id' => $this->_ids['price_field'],
1669 'financial_type_id' => 'Member Dues',
1670 ]);
1671 $this->_ids['price_field_value_yearly'] = $priceFieldValueYearly['id'];
1672
1673 CRM_Price_BAO_PriceSet::addTo('civicrm_contribution_page', $this->_ids['contribution_page'], $this->_ids['price_set']);
1674
1675 $this->callAPISuccess('membership_block', 'create', [
1676 'entity_id' => $this->_ids['contribution_page'],
1677 'entity_table' => 'civicrm_contribution_page',
1678 'is_required' => TRUE,
1679 'is_separate_payment' => FALSE,
1680 'is_active' => TRUE,
1681 'membership_type_default' => $this->_ids['membership_type'],
1682 ]);
1683 }
1684
1685 /**
1686 * Test submit with a membership block in place.
1687 *
1688 * @throws \CRM_Core_Exception
1689 */
1690 public function testSubmitMultiIntervalMembershipContributionPage() {
1691 $this->setUpMultiIntervalMembershipContributionPage();
1692 $submitParams = [
1693 'price_' . $this->_ids['price_field'] => $this->_ids['price_field_value_monthly'],
1694 'id' => (int) $this->_ids['contribution_page'],
1695 'amount' => 20,
1696 'first_name' => 'Billy',
1697 'last_name' => 'Gruff',
1698 'email' => 'billy@goat.gruff',
1699 'payment_processor_id' => $this->_ids['payment_processor'],
1700 'credit_card_number' => '4111111111111111',
1701 'credit_card_type' => 'Visa',
1702 'credit_card_exp_date' => ['M' => 9, 'Y' => 2040],
1703 'cvv2' => 123,
1704 'auto_renew' => 1,
1705 ];
1706 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
1707
1708 $submitParams['price_' . $this->_ids['price_field']] = $this->_ids['price_field_value_yearly'];
1709 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
1710
1711 $contribution = $this->callAPISuccess('Contribution', 'get', [
1712 'contribution_page_id' => $this->_ids['contribution_page'],
1713 'sequential' => 1,
1714 'api.ContributionRecur.getsingle' => [],
1715 ]);
1716 $this->assertEquals(1, $contribution['values'][0]['api.ContributionRecur.getsingle']['frequency_interval']);
1717 //$this->assertEquals(12, $contribution['values'][1]['api.ContributionRecur.getsingle']['frequency_interval']);
1718 }
1719
1720 public static function setUpBeforeClass() {
1721 // put stuff here that should happen before all tests in this unit
1722 }
1723
1724 /**
1725 * Create a payment processor instance.
1726 *
1727 * @throws \CRM_Core_Exception
1728 */
1729 protected function setupPaymentProcessor() {
1730 $this->params['payment_processor_id'] = $this->_ids['payment_processor'] = $this->paymentProcessorCreate([
1731 'payment_processor_type_id' => 'Dummy',
1732 'class_name' => 'Payment_Dummy',
1733 'billing_mode' => 1,
1734 ]);
1735 $this->_paymentProcessor = $this->callAPISuccess('payment_processor', 'getsingle', ['id' => $this->params['payment_processor_id']]);
1736 }
1737
1738 /**
1739 * Test submit recurring pledge.
1740 *
1741 * - we process 1 pledge with a future start date. A recur contribution and the pledge should be created with first payment date in the future.
1742 *
1743 * @throws \CRM_Core_Exception
1744 */
1745 public function testSubmitPledgePaymentPaymentProcessorRecurFuturePayment() {
1746 $this->params['adjust_recur_start_date'] = TRUE;
1747 $this->params['is_pay_later'] = FALSE;
1748 $this->setUpContributionPage();
1749 $this->setUpPledgeBlock();
1750 $this->setupPaymentProcessor();
1751 $dummyPP = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
1752 $dummyPP->setDoDirectPaymentResult(['payment_status_id' => 1, 'trxn_id' => 'create_first_success']);
1753
1754 $submitParams = [
1755 'id' => (int) $this->_ids['contribution_page'],
1756 'amount' => 100,
1757 'billing_first_name' => 'Billy',
1758 'billing_middle_name' => 'Goat',
1759 'billing_last_name' => 'Gruff',
1760 'email' => 'billy@goat.gruff',
1761 'payment_processor_id' => 1,
1762 'credit_card_number' => '4111111111111111',
1763 'credit_card_type' => 'Visa',
1764 'credit_card_exp_date' => ['M' => 9, 'Y' => 2040],
1765 'cvv2' => 123,
1766 'pledge_frequency_interval' => 1,
1767 'pledge_frequency_unit' => 'week',
1768 'pledge_installments' => 3,
1769 'is_pledge' => TRUE,
1770 'pledge_block_id' => (int) $this->_ids['pledge_block_id'],
1771 ];
1772
1773 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL);
1774
1775 // Check if contribution created.
1776 $contribution = $this->callAPISuccess('contribution', 'getsingle', [
1777 'contribution_page_id' => $this->_ids['contribution_page'],
1778 // Will be pending when actual payment processor is used (dummy processor does not support future payments).
1779 'contribution_status_id' => 'Completed',
1780 ]);
1781
1782 $this->assertEquals('create_first_success', $contribution['trxn_id']);
1783
1784 // Check if pledge created.
1785 $pledge = $this->callAPISuccess('pledge', 'getsingle', []);
1786 $this->assertEquals(date('Ymd', strtotime($pledge['pledge_start_date'])), date('Ymd', strtotime("+1 month")));
1787 $this->assertEquals($pledge['pledge_amount'], 300.00);
1788
1789 // Check if pledge payments created.
1790 $params = [
1791 'pledge_id' => $pledge['id'],
1792 ];
1793 $pledgePayment = $this->callAPISuccess('pledge_payment', 'get', $params);
1794 $this->assertEquals($pledgePayment['count'], 3);
1795 $this->assertEquals(date('Ymd', strtotime($pledgePayment['values'][1]['scheduled_date'])), date('Ymd', strtotime("+1 month")));
1796 $this->assertEquals($pledgePayment['values'][1]['scheduled_amount'], 100.00);
1797 // Will be pending when actual payment processor is used (dummy processor does not support future payments).
1798 $this->assertEquals($pledgePayment['values'][1]['status_id'], 1);
1799
1800 // Check contribution recur record.
1801 $recur = $this->callAPISuccess('contribution_recur', 'getsingle', ['id' => $contribution['contribution_recur_id']]);
1802 $this->assertEquals(date('Ymd', strtotime($recur['start_date'])), date('Ymd', strtotime("+1 month")));
1803 $this->assertEquals($recur['amount'], 100.00);
1804 // In progress status.
1805 $this->assertEquals($recur['contribution_status_id'], 5);
1806 }
1807
1808 /**
1809 * Test submit pledge payment.
1810 *
1811 * - test submitting a pledge payment using contribution form.
1812 *
1813 * @throws \CRM_Core_Exception
1814 */
1815 public function testSubmitPledgePayment() {
1816 $this->testSubmitPledgePaymentPaymentProcessorRecurFuturePayment();
1817 $pledge = $this->callAPISuccess('pledge', 'getsingle', []);
1818 $params = [
1819 'pledge_id' => $pledge['id'],
1820 ];
1821 $submitParams = [
1822 'id' => (int) $pledge['pledge_contribution_page_id'],
1823 'pledge_amount' => [2 => 1],
1824 'billing_first_name' => 'Billy',
1825 'billing_middle_name' => 'Goat',
1826 'billing_last_name' => 'Gruff',
1827 'email' => 'billy@goat.gruff',
1828 'payment_processor_id' => 1,
1829 'credit_card_number' => '4111111111111111',
1830 'credit_card_type' => 'Visa',
1831 'credit_card_exp_date' => ['M' => 9, 'Y' => 2040],
1832 'cvv2' => 123,
1833 'pledge_id' => $pledge['id'],
1834 'cid' => $pledge['contact_id'],
1835 'contact_id' => $pledge['contact_id'],
1836 'amount' => 100.00,
1837 'is_pledge' => TRUE,
1838 'pledge_block_id' => $this->_ids['pledge_block_id'],
1839 ];
1840 $pledgePayment = $this->callAPISuccess('pledge_payment', 'get', $params);
1841 $this->assertEquals($pledgePayment['values'][2]['status_id'], 2);
1842
1843 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL);
1844
1845 // Check if contribution created.
1846 $contribution = $this->callAPISuccess('contribution', 'getsingle', [
1847 'contribution_page_id' => $pledge['pledge_contribution_page_id'],
1848 'contribution_status_id' => 'Completed',
1849 'contact_id' => $pledge['contact_id'],
1850 'contribution_recur_id' => ['IS NULL' => 1],
1851 ]);
1852
1853 $this->assertEquals(100.00, $contribution['total_amount']);
1854 $pledgePayment = $this->callAPISuccess('pledge_payment', 'get', $params);
1855 $this->assertEquals($pledgePayment['values'][2]['status_id'], 1, "This pledge payment should have been completed");
1856 $this->assertEquals($pledgePayment['values'][2]['contribution_id'], $contribution['id']);
1857 }
1858
1859 /**
1860 * Test form submission with multiple option price set.
1861 *
1862 * @param string $thousandSeparator
1863 * punctuation used to refer to thousands.
1864 *
1865 * @dataProvider getThousandSeparators
1866 * @throws \CRM_Core_Exception
1867 */
1868 public function testSubmitContributionPageWithPriceSet($thousandSeparator) {
1869 $this->setCurrencySeparators($thousandSeparator);
1870 $this->_priceSetParams['is_quick_config'] = 0;
1871 $this->setUpContributionPage();
1872 $submitParams = [
1873 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
1874 'id' => (int) $this->_ids['contribution_page'],
1875 'amount' => 80,
1876 'first_name' => 'Billy',
1877 'last_name' => 'Gruff',
1878 'email' => 'billy@goat.gruff',
1879 'is_pay_later' => TRUE,
1880 ];
1881 $this->addPriceFields($submitParams);
1882
1883 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
1884 $contribution = $this->callAPISuccessGetSingle('contribution', [
1885 'contribution_page_id' => $this->_ids['contribution_page'],
1886 'contribution_status_id' => 'Pending',
1887 ]);
1888 $this->assertEquals(80, $contribution['total_amount']);
1889 $lineItems = $this->callAPISuccess('LineItem', 'get', [
1890 'contribution_id' => $contribution['id'],
1891 ]);
1892 $this->assertEquals(3, $lineItems['count']);
1893 $totalLineAmount = 0;
1894 foreach ($lineItems['values'] as $lineItem) {
1895 $totalLineAmount = $totalLineAmount + $lineItem['line_total'];
1896 }
1897 $this->assertEquals(80, $totalLineAmount);
1898 }
1899
1900 /**
1901 * Function to add additional price fields to priceset.
1902 *
1903 * @param array $params
1904 *
1905 * @throws \CRM_Core_Exception
1906 */
1907 public function addPriceFields(&$params) {
1908 $priceSetID = reset($this->_ids['price_set']);
1909 $priceField = $this->callAPISuccess('price_field', 'create', [
1910 'price_set_id' => $priceSetID,
1911 'label' => 'Chicken Breed',
1912 'html_type' => 'CheckBox',
1913 ]);
1914 $priceFieldValue1 = $this->callAPISuccess('price_field_value', 'create', [
1915 'price_set_id' => $priceSetID,
1916 'price_field_id' => $priceField['id'],
1917 'label' => 'Shoe-eating chicken -1',
1918 'financial_type_id' => 'Donation',
1919 'amount' => 30,
1920 ]);
1921 $priceFieldValue2 = $this->callAPISuccess('price_field_value', 'create', [
1922 'price_set_id' => $priceSetID,
1923 'price_field_id' => $priceField['id'],
1924 'label' => 'Shoe-eating chicken -2',
1925 'financial_type_id' => 'Donation',
1926 'amount' => 40,
1927 ]);
1928 $params['price_' . $priceField['id']] = [
1929 $priceFieldValue1['id'] => 1,
1930 $priceFieldValue2['id'] => 1,
1931 ];
1932 }
1933
1934 /**
1935 * Test Tax Amount is calculated properly when using PriceSet with Field Type = Text/Numeric Quantity
1936 *
1937 * @param string $thousandSeparator
1938 * punctuation used to refer to thousands.
1939 *
1940 * @dataProvider getThousandSeparators
1941 * @throws \CRM_Core_Exception
1942 */
1943 public function testSubmitContributionPageWithPriceSetQuantity($thousandSeparator) {
1944 $this->setCurrencySeparators($thousandSeparator);
1945 $this->_priceSetParams['is_quick_config'] = 0;
1946 $this->enableTaxAndInvoicing();
1947 $financialType = $this->createFinancialType();
1948 $financialTypeId = $financialType['id'];
1949 // This function sets the Tax Rate at 10% - it currently has no way to pass Tax Rate into it - so let's work with 10%
1950 $this->relationForFinancialTypeWithFinancialAccount($financialType['id'], 5);
1951
1952 $this->setUpContributionPage();
1953 $submitParams = [
1954 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
1955 'id' => (int) $this->_ids['contribution_page'],
1956 'first_name' => 'J',
1957 'last_name' => 'T',
1958 'email' => 'JT@ohcanada.ca',
1959 'is_pay_later' => TRUE,
1960 'receive_date' => date('Y-m-d H:i:s'),
1961 ];
1962
1963 // Create PriceSet/PriceField
1964 $priceSetID = reset($this->_ids['price_set']);
1965 $priceField = $this->callAPISuccess('price_field', 'create', [
1966 'price_set_id' => $priceSetID,
1967 'label' => 'Printing Rights',
1968 'html_type' => 'Text',
1969 ]);
1970 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', [
1971 'price_set_id' => $priceSetID,
1972 'price_field_id' => $priceField['id'],
1973 'label' => 'Printing Rights',
1974 'financial_type_id' => $financialTypeId,
1975 'amount' => '16.95',
1976 ]);
1977 $priceFieldId = $priceField['id'];
1978
1979 // Set quantity for our test
1980 $submitParams['price_' . $priceFieldId] = 180;
1981
1982 // contribution_page submit requires amount and tax_amount - and that's ok we're not testing that - we're testing at the LineItem level
1983 $submitParams['amount'] = $this->formatMoneyInput(180 * 16.95);
1984 // This is the correct Tax Amount - use it later to compare to what the CiviCRM Core came up with at the LineItem level
1985 $submitParams['tax_amount'] = $this->formatMoneyInput(180 * 16.95 * 0.10);
1986
1987 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
1988 $contribution = $this->callAPISuccessGetSingle('contribution', [
1989 'contribution_page_id' => $this->_ids['contribution_page'],
1990 ]);
1991
1992 // Retrieve the lineItem that belongs to the Printing Rights and check the tax_amount CiviCRM Core calculated for it
1993 $lineItem = $this->callAPISuccessGetSingle('LineItem', [
1994 'contribution_id' => $contribution['id'],
1995 'label' => 'Printing Rights',
1996 ]);
1997
1998 $lineItem_TaxAmount = round($lineItem['tax_amount'], 2);
1999
2000 $this->assertEquals($lineItem['line_total'], $contribution['total_amount'], 'Contribution total should match line total');
2001 $this->assertEquals($lineItem_TaxAmount, round(180 * 16.95 * 0.10, 2), 'Wrong Sales Tax Amount is calculated and stored.');
2002 }
2003
2004 /**
2005 * Test validating a contribution page submit.
2006 *
2007 * @throws \CRM_Core_Exception
2008 */
2009 public function testValidate() {
2010 $this->setUpContributionPage();
2011 $errors = $this->callAPISuccess('ContributionPage', 'validate', array_merge($this->getBasicSubmitParams(), ['action' => 'submit']))['values'];
2012 $this->assertEmpty($errors);
2013 }
2014
2015 /**
2016 * Test validating a contribution page submit in POST context.
2017 *
2018 * A likely use case for the validation is when the is being submitted and some handling is
2019 * to be done before processing but the validity of input needs to be checked first.
2020 *
2021 * For example Paypal Checkout will replace the confirm button with it's own but we are able to validate
2022 * before paypal launches it's modal. In this case the $_REQUEST is post but we need validation to succeed.
2023 */
2024 public function testValidatePost() {
2025 $_SERVER['REQUEST_METHOD'] = 'POST';
2026 $this->setUpContributionPage();
2027 $errors = $this->callAPISuccess('ContributionPage', 'validate', array_merge($this->getBasicSubmitParams(), ['action' => 'submit']))['values'];
2028 $this->assertEmpty($errors);
2029 unset($_SERVER['REQUEST_METHOD']);
2030 }
2031
2032 /**
2033 * Test that an error is generated if required fields are not submitted.
2034 */
2035 public function testValidateOutputOnMissingRecurFields() {
2036 $this->params['is_recur_interval'] = 1;
2037 $this->setUpContributionPage(TRUE);
2038 $submitParams = array_merge($this->getBasicSubmitParams(), ['action' => 'submit']);
2039 $submitParams['is_recur'] = 1;
2040 $submitParams['frequency_interval'] = '';
2041 $submitParams['frequency_unit'] = '';
2042 $errors = $this->callAPISuccess('ContributionPage', 'validate', $submitParams)['values'];
2043 $this->assertEquals('Please enter a number for how often you want to make this recurring contribution (EXAMPLE: Every 3 months).', $errors['frequency_interval']);
2044 }
2045
2046 /**
2047 * Implements hook_civicrm_alterPaymentProcessorParams().
2048 *
2049 * @throws \Exception
2050 */
2051 public function hook_civicrm_alterPaymentProcessorParams($paymentObj, &$rawParams, &$cookedParams) {
2052 // Ensure total_amount are the same if they're both given.
2053 $total_amount = CRM_Utils_Array::value('total_amount', $rawParams);
2054 $amount = CRM_Utils_Array::value('amount', $rawParams);
2055 if (!empty($total_amount) && !empty($amount) && $total_amount != $amount) {
2056 throw new Exception("total_amount '$total_amount' and amount '$amount' differ.");
2057 }
2058
2059 // Log parameters for later debugging and testing.
2060 $message = __FUNCTION__ . ": {$rawParams['TEST_UNIQ']}:";
2061 $log_params = array_intersect_key($rawParams, [
2062 'amount' => 1,
2063 'total_amount' => 1,
2064 'contributionID' => 1,
2065 ]);
2066 $message .= json_encode($log_params);
2067 $log = new CRM_Utils_SystemLogger();
2068 $log->debug($message, $_REQUEST);
2069 }
2070
2071 /**
2072 * Get the params for a basic simple submit.
2073 *
2074 * @return array
2075 */
2076 protected function getBasicSubmitParams() {
2077 $priceFieldID = reset($this->_ids['price_field']);
2078 $priceFieldValueID = reset($this->_ids['price_field_value']);
2079 $submitParams = [
2080 'price_' . $priceFieldID => $priceFieldValueID,
2081 'id' => (int) $this->_ids['contribution_page'],
2082 'amount' => 10,
2083 'priceSetId' => $this->_ids['price_set'][0],
2084 'payment_processor_id' => 0,
2085 ];
2086 return $submitParams;
2087 }
2088
2089 }