3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2016 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
29 * Test APIv3 civicrm_contribute_recur* functions
31 * @package CiviCRM_APIv3
32 * @subpackage API_Contribution
35 class api_v3_ContributionPageTest
extends CiviUnitTestCase
{
36 protected $_apiversion = 3;
37 protected $testAmount = 34567;
40 protected $contactIds = array();
41 protected $_entity = 'contribution_page';
42 protected $contribution_result = NULL;
43 protected $_priceSetParams = array();
45 * Payment processor details.
48 protected $_paymentProcessor = array();
57 protected $_ids = array();
60 public $DBResetRequired = TRUE;
62 public function setUp() {
64 $this->contactIds
[] = $this->individualCreate();
65 $this->params
= array(
66 'title' => "Test Contribution Page",
67 'financial_type_id' => 1,
69 'goal_amount' => $this->testAmount
,
71 'is_monetary' => TRUE,
72 'is_email_receipt' => TRUE,
73 'receipt_from_email' => 'yourconscience@donate.com',
74 'receipt_from_name' => 'Ego Freud',
77 $this->_priceSetParams
= array(
78 'is_quick_config' => 1,
79 'extends' => 'CiviContribute',
80 'financial_type_id' => 'Donation',
85 public function tearDown() {
86 foreach ($this->contactIds
as $id) {
87 $this->callAPISuccess('contact', 'delete', array('id' => $id));
89 $this->quickCleanUpFinancialEntities();
92 public function testCreateContributionPage() {
93 $result = $this->callAPIAndDocument($this->_entity
, 'create', $this->params
, __FUNCTION__
, __FILE__
);
94 $this->assertEquals(1, $result['count']);
95 $this->assertNotNull($result['values'][$result['id']]['id']);
96 $this->getAndCheck($this->params
, $result['id'], $this->_entity
);
99 public function testGetBasicContributionPage() {
100 $createResult = $this->callAPISuccess($this->_entity
, 'create', $this->params
);
101 $this->id
= $createResult['id'];
104 'financial_type_id' => 1,
106 $getResult = $this->callAPIAndDocument($this->_entity
, 'get', $getParams, __FUNCTION__
, __FILE__
);
107 $this->assertEquals(1, $getResult['count']);
110 public function testGetContributionPageByAmount() {
111 $createResult = $this->callAPISuccess($this->_entity
, 'create', $this->params
);
112 $this->id
= $createResult['id'];
114 'amount' => '' . $this->testAmount
, // 3456
116 'financial_type_id' => 1,
118 $getResult = $this->callAPIAndDocument($this->_entity
, 'get', $getParams, __FUNCTION__
, __FILE__
);
119 $this->assertEquals(1, $getResult['count']);
122 public function testDeleteContributionPage() {
123 $createResult = $this->callAPISuccess($this->_entity
, 'create', $this->params
);
124 $deleteParams = array('id' => $createResult['id']);
125 $this->callAPIAndDocument($this->_entity
, 'delete', $deleteParams, __FUNCTION__
, __FILE__
);
126 $checkDeleted = $this->callAPISuccess($this->_entity
, 'get', array());
127 $this->assertEquals(0, $checkDeleted['count']);
130 public function testGetFieldsContributionPage() {
131 $result = $this->callAPISuccess($this->_entity
, 'getfields', array('action' => 'create'));
132 $this->assertEquals(12, $result['values']['start_date']['type']);
137 * Test form submission with basic price set.
139 public function testSubmit() {
140 $this->setUpContributionPage();
141 $priceFieldID = reset($this->_ids
['price_field']);
142 $priceFieldValueID = reset($this->_ids
['price_field_value']);
143 $submitParams = array(
144 'price_' . $priceFieldID => $priceFieldValueID,
145 'id' => (int) $this->_ids
['contribution_page'],
149 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
150 $this->callAPISuccess('contribution', 'getsingle', array('contribution_page_id' => $this->_ids
['contribution_page']));
154 * Test form submission with billing first & last name where the contact does NOT
155 * otherwise have one.
157 public function testSubmitNewBillingNameData() {
158 $this->setUpContributionPage();
159 $contact = $this->callAPISuccess('Contact', 'create', array('contact_type' => 'Individual', 'email' => 'wonderwoman@amazon.com'));
160 $priceFieldID = reset($this->_ids
['price_field']);
161 $priceFieldValueID = reset($this->_ids
['price_field_value']);
162 $submitParams = array(
163 'price_' . $priceFieldID => $priceFieldValueID,
164 'id' => (int) $this->_ids
['contribution_page'],
166 'billing_first_name' => 'Wonder',
167 'billing_last_name' => 'Woman',
168 'contactID' => $contact['id'],
169 'email' => 'wonderwoman@amazon.com',
172 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
173 $contact = $this->callAPISuccess('Contact', 'get', array(
174 'id' => $contact['id'],
182 $this->assertEquals(array(
183 'first_name' => 'Wonder',
184 'last_name' => 'Woman',
185 'display_name' => 'Wonder Woman',
186 'sort_name' => 'Woman, Wonder',
187 'id' => $contact['id'],
188 'contact_id' => $contact['id'],
189 ), $contact['values'][$contact['id']]);
194 * Test form submission with billing first & last name where the contact does
195 * otherwise have one and should not be overwritten.
197 public function testSubmitNewBillingNameDoNotOverwrite() {
198 $this->setUpContributionPage();
199 $contact = $this->callAPISuccess('Contact', 'create', array(
200 'contact_type' => 'Individual',
201 'email' => 'wonderwoman@amazon.com',
202 'first_name' => 'Super',
203 'last_name' => 'Boy',
205 $priceFieldID = reset($this->_ids
['price_field']);
206 $priceFieldValueID = reset($this->_ids
['price_field_value']);
207 $submitParams = array(
208 'price_' . $priceFieldID => $priceFieldValueID,
209 'id' => (int) $this->_ids
['contribution_page'],
211 'billing_first_name' => 'Wonder',
212 'billing_last_name' => 'Woman',
213 'contactID' => $contact['id'],
214 'email' => 'wonderwoman@amazon.com',
217 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
218 $contact = $this->callAPISuccess('Contact', 'get', array(
219 'id' => $contact['id'],
227 $this->assertEquals(array(
228 'first_name' => 'Super',
229 'last_name' => 'Boy',
230 'display_name' => 'Super Boy',
231 'sort_name' => 'Boy, Super',
232 'id' => $contact['id'],
233 'contact_id' => $contact['id'],
234 ), $contact['values'][$contact['id']]);
239 * Test process with instant payment when more than one configured for the page.
243 public function testSubmitRecurMultiProcessorInstantPayment() {
244 $this->setUpContributionPage();
245 $this->setupPaymentProcessor();
246 $paymentProcessor2ID = $this->paymentProcessorCreate(array(
247 'payment_processor_type_id' => 'Dummy',
248 'name' => 'processor 2',
249 'class_name' => 'Payment_Dummy',
252 $dummyPP = Civi\Payment\System
::singleton()->getById($paymentProcessor2ID);
253 $dummyPP->setDoDirectPaymentResult(array(
254 'payment_status_id' => 1,
255 'trxn_id' => 'create_first_success',
258 $this->callAPISuccess('ContributionPage', 'create', array(
259 'id' => $this->_ids
['contribution_page'],
260 'payment_processor' => array($paymentProcessor2ID, $this->_ids
['payment_processor']),
263 $priceFieldID = reset($this->_ids
['price_field']);
264 $priceFieldValueID = reset($this->_ids
['price_field_value']);
265 $submitParams = array(
266 'price_' . $priceFieldID => $priceFieldValueID,
267 'id' => (int) $this->_ids
['contribution_page'],
270 'frequency_interval' => 1,
271 'frequency_unit' => 'month',
272 'payment_processor_id' => $paymentProcessor2ID,
275 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
276 $contribution = $this->callAPISuccess('contribution', 'getsingle', array(
277 'contribution_page_id' => $this->_ids
['contribution_page'],
278 'contribution_status_id' => 1,
280 $this->assertEquals('create_first_success', $contribution['trxn_id']);
281 $this->assertEquals(10, $contribution['total_amount']);
282 $this->assertEquals(.85, $contribution['fee_amount']);
283 $this->assertEquals(9.15, $contribution['net_amount']);
284 $this->_checkFinancialRecords(array(
285 'id' => $contribution['id'],
286 'total_amount' => $contribution['total_amount'],
291 * Test submit with a membership block in place.
293 public function testSubmitMembershipBlockNotSeparatePayment() {
294 $this->setUpMembershipContributionPage();
295 $submitParams = array(
296 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
297 'id' => (int) $this->_ids
['contribution_page'],
299 'billing_first_name' => 'Billy',
300 'billing_middle_name' => 'Goat',
301 'billing_last_name' => 'Gruff',
302 'selectMembership' => $this->_ids
['membership_type'],
306 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
307 $contribution = $this->callAPISuccess('contribution', 'getsingle', array('contribution_page_id' => $this->_ids
['contribution_page']));
308 $this->callAPISuccess('membership_payment', 'getsingle', array('contribution_id' => $contribution['id']));
312 * Test submit with a membership block in place.
314 public function testSubmitMembershipBlockNotSeparatePaymentWithEmail() {
315 $mut = new CiviMailUtils($this, TRUE);
316 $this->setUpMembershipContributionPage();
317 $this->addProfile('supporter_profile', $this->_ids
['contribution_page']);
319 $submitParams = array(
320 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
321 'id' => (int) $this->_ids
['contribution_page'],
323 'billing_first_name' => 'Billy',
324 'billing_middle_name' => 'Goat',
325 'billing_last_name' => 'Gruff',
326 'selectMembership' => $this->_ids
['membership_type'],
327 'email-Primary' => 'billy-goat@the-bridge.net',
328 'payment_processor_id' => $this->_paymentProcessor
['id'],
329 'credit_card_number' => '4111111111111111',
330 'credit_card_type' => 'Visa',
331 'credit_card_exp_date' => array('M' => 9, 'Y' => 2040),
335 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
336 $contribution = $this->callAPISuccess('contribution', 'getsingle', array('contribution_page_id' => $this->_ids
['contribution_page']));
337 $this->callAPISuccess('membership_payment', 'getsingle', array('contribution_id' => $contribution['id']));
338 $mut->checkMailLog(array(
339 'Membership Type: General',
342 $mut->clearMessages();
346 * Test submit with a membership block in place.
348 public function testSubmitMembershipBlockNotSeparatePaymentZeroDollarsWithEmail() {
349 $mut = new CiviMailUtils($this, TRUE);
350 $this->_ids
['membership_type'] = array($this->membershipTypeCreate(array('minimum_fee' => 0)));
351 $this->setUpMembershipContributionPage();
352 $this->addProfile('supporter_profile', $this->_ids
['contribution_page']);
354 $submitParams = array(
355 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
356 'id' => (int) $this->_ids
['contribution_page'],
358 'billing_first_name' => 'Billy',
359 'billing_middle_name' => 'Goat',
360 'billing_last_name' => 'Gruffier',
361 'selectMembership' => $this->_ids
['membership_type'],
362 'email-Primary' => 'billy-goat@the-new-bridge.net',
365 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
366 $contribution = $this->callAPISuccess('contribution', 'getsingle', array('contribution_page_id' => $this->_ids
['contribution_page']));
367 $this->callAPISuccess('membership_payment', 'getsingle', array('contribution_id' => $contribution['id']));
368 $mut->checkMailLog(array(
369 'Membership Type: General',
377 $mut->clearMessages(999);
381 * Test submit with a membership block in place.
383 public function testSubmitMembershipBlockIsSeparatePayment() {
384 $this->setUpMembershipContributionPage(TRUE);
385 $this->_ids
['membership_type'] = array($this->membershipTypeCreate(array('minimum_fee' => 2)));
386 $submitParams = array(
387 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
388 'id' => (int) $this->_ids
['contribution_page'],
390 'billing_first_name' => 'Billy',
391 'billing_middle_name' => 'Goat',
392 'billing_last_name' => 'Gruff',
393 'selectMembership' => $this->_ids
['membership_type'],
396 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
397 $contributions = $this->callAPISuccess('contribution', 'get', array('contribution_page_id' => $this->_ids
['contribution_page']));
398 $this->assertCount(2, $contributions['values']);
399 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
400 $this->assertTrue(in_array($membershipPayment['contribution_id'], array_keys($contributions['values'])));
401 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
402 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
406 * Test submit with a membership block in place.
408 public function testSubmitMembershipBlockIsSeparatePaymentWithEmail() {
409 $mut = new CiviMailUtils($this, TRUE);
410 $this->setUpMembershipContributionPage(TRUE);
411 $this->addProfile('supporter_profile', $this->_ids
['contribution_page']);
413 $submitParams = array(
414 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
415 'id' => (int) $this->_ids
['contribution_page'],
417 'billing_first_name' => 'Billy',
418 'billing_middle_name' => 'Goat',
419 'billing_last_name' => 'Gruff',
420 'selectMembership' => $this->_ids
['membership_type'],
421 'email-Primary' => 'billy-goat@the-bridge.net',
422 'payment_processor_id' => $this->_paymentProcessor
['id'],
423 'credit_card_number' => '4111111111111111',
424 'credit_card_type' => 'Visa',
425 'credit_card_exp_date' => array('M' => 9, 'Y' => 2040),
429 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
430 $contributions = $this->callAPISuccess('contribution', 'get', array('contribution_page_id' => $this->_ids
['contribution_page']));
431 $this->assertCount(2, $contributions['values']);
432 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
433 $this->assertTrue(in_array($membershipPayment['contribution_id'], array_keys($contributions['values'])));
434 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
435 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
436 $mut->checkAllMailLog(array(
441 $mut->clearMessages(999);
445 * Test submit with a membership block in place.
447 public function testSubmitMembershipBlockIsSeparatePaymentZeroDollarsPayLaterWithEmail() {
448 $mut = new CiviMailUtils($this, TRUE);
449 $this->_ids
['membership_type'] = array($this->membershipTypeCreate(array('minimum_fee' => 0)));
450 $this->setUpMembershipContributionPage(TRUE);
451 $this->addProfile('supporter_profile', $this->_ids
['contribution_page']);
453 $submitParams = array(
454 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
455 'id' => (int) $this->_ids
['contribution_page'],
457 'billing_first_name' => 'Billy',
458 'billing_middle_name' => 'Goat',
459 'billing_last_name' => 'Gruffalo',
460 'selectMembership' => $this->_ids
['membership_type'],
461 'payment_processor_id' => 0,
462 'email-Primary' => 'gruffalo@the-bridge.net',
465 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
466 $contributions = $this->callAPISuccess('contribution', 'get', array('contribution_page_id' => $this->_ids
['contribution_page']));
467 $this->assertCount(2, $contributions['values']);
468 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
469 $this->assertTrue(in_array($membershipPayment['contribution_id'], array_keys($contributions['values'])));
470 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
471 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
472 $mut->checkMailLog(array(
474 'General Membership: $ 0.00',
478 $mut->clearMessages();
482 * Test submit with a membership block in place.
484 public function testSubmitMembershipBlockTwoTypesIsSeparatePayment() {
485 $this->_ids
['membership_type'] = array($this->membershipTypeCreate(array('minimum_fee' => 6)));
486 $this->_ids
['membership_type'][] = $this->membershipTypeCreate(array('name' => 'Student', 'minimum_fee' => 50));
487 $this->setUpMembershipContributionPage(TRUE);
488 $submitParams = array(
489 'price_' . $this->_ids
['price_field'][0] => $this->_ids
['price_field_value'][1],
490 'id' => (int) $this->_ids
['contribution_page'],
492 'billing_first_name' => 'Billy',
493 'billing_middle_name' => 'Goat',
494 'billing_last_name' => 'Gruff',
495 'selectMembership' => $this->_ids
['membership_type'][1],
498 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
499 $contributions = $this->callAPISuccess('contribution', 'get', array('contribution_page_id' => $this->_ids
['contribution_page']));
500 $this->assertCount(2, $contributions['values']);
501 $ids = array_keys($contributions['values']);
502 $this->assertEquals('10.00', $contributions['values'][$ids[0]]['total_amount']);
503 $this->assertEquals('50.00', $contributions['values'][$ids[1]]['total_amount']);
504 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
505 $this->assertArrayHasKey($membershipPayment['contribution_id'], $contributions['values']);
506 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
507 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
511 * Test submit with a membership block in place.
513 * We are expecting a separate payment for the membership vs the contribution.
515 public function testSubmitMembershipBlockIsSeparatePaymentPaymentProcessorNow() {
516 $this->setUpMembershipContributionPage(TRUE);
517 $processor = Civi\Payment\System
::singleton()->getById($this->_paymentProcessor
['id']);
518 $processor->setDoDirectPaymentResult(array('fee_amount' => .72));
519 $submitParams = array(
520 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
521 'id' => (int) $this->_ids
['contribution_page'],
523 'billing_first_name' => 'Billy',
524 'billing_middle_name' => 'Goat',
525 'billing_last_name' => 'Gruff',
526 'selectMembership' => $this->_ids
['membership_type'],
527 'payment_processor_id' => $this->_paymentProcessor
['id'],
528 'credit_card_number' => '4111111111111111',
529 'credit_card_type' => 'Visa',
530 'credit_card_exp_date' => array('M' => 9, 'Y' => 2040),
534 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
535 $contributions = $this->callAPISuccess('contribution', 'get', array(
536 'contribution_page_id' => $this->_ids
['contribution_page'],
537 'contribution_status_id' => 1,
539 $this->assertCount(2, $contributions['values']);
540 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
541 $this->assertTrue(in_array($membershipPayment['contribution_id'], array_keys($contributions['values'])));
542 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
543 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
544 foreach ($contributions['values'] as $contribution) {
545 $this->assertEquals(.72, $contribution['fee_amount']);
546 $this->assertEquals($contribution['total_amount'] - .72, $contribution['net_amount']);
551 * Test that when a transaction fails the pending contribution remains.
553 * An activity should also be created. CRM-16417.
555 public function testSubmitPaymentProcessorFailure() {
556 $this->setUpContributionPage();
557 $this->setupPaymentProcessor();
558 $this->createLoggedInUser();
559 $priceFieldID = reset($this->_ids
['price_field']);
560 $priceFieldValueID = reset($this->_ids
['price_field_value']);
561 $submitParams = array(
562 'price_' . $priceFieldID => $priceFieldValueID,
563 'id' => (int) $this->_ids
['contribution_page'],
565 'payment_processor_id' => 1,
566 'credit_card_number' => '4111111111111111',
567 'credit_card_type' => 'Visa',
568 'credit_card_exp_date' => array('M' => 9, 'Y' => 2008),
572 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
573 $contribution = $this->callAPISuccessGetSingle('contribution', array(
574 'contribution_page_id' => $this->_ids
['contribution_page'],
575 'contribution_status_id' => 2,
578 $this->callAPISuccessGetSingle('activity', array(
579 'source_record_id' => $contribution['id'],
580 'activity_type_id' => 'Failed Payment',
586 * Test submit recurring membership with immediate confirmation (IATS style).
588 * - we process 2 membership transactions against with a recurring contribution against a contribution page with an immediate
589 * processor (IATS style - denoted by returning trxn_id)
590 * - the first creates a new membership, completed contribution, in progress recurring. Check these
591 * - create another - end date should be extended
593 public function testSubmitMembershipPriceSetPaymentPaymentProcessorRecurInstantPayment() {
594 $this->params
['is_recur'] = 1;
595 $this->params
['recur_frequency_unit'] = 'month';
596 $this->setUpMembershipContributionPage();
597 $dummyPP = Civi\Payment\System
::singleton()->getByProcessor($this->_paymentProcessor
);
598 $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 1, 'trxn_id' => 'create_first_success'));
600 $submitParams = array(
601 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
602 'id' => (int) $this->_ids
['contribution_page'],
604 'billing_first_name' => 'Billy',
605 'billing_middle_name' => 'Goat',
606 'billing_last_name' => 'Gruff',
607 'email' => 'billy@goat.gruff',
608 'selectMembership' => $this->_ids
['membership_type'],
609 'payment_processor_id' => 1,
610 'credit_card_number' => '4111111111111111',
611 'credit_card_type' => 'Visa',
612 'credit_card_exp_date' => array('M' => 9, 'Y' => 2040),
615 'frequency_interval' => 1,
616 'frequency_unit' => 'month',
619 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
620 $contribution = $this->callAPISuccess('contribution', 'getsingle', array(
621 'contribution_page_id' => $this->_ids
['contribution_page'],
622 'contribution_status_id' => 1,
625 $this->assertEquals('create_first_success', $contribution['trxn_id']);
626 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
627 $this->assertEquals($membershipPayment['contribution_id'], $contribution['id']);
628 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
629 $this->assertEquals($membership['contact_id'], $contribution['contact_id']);
630 $this->assertEquals(1, $membership['status_id']);
631 $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $contribution['contribution_recur_id']));
632 //@todo - check with Joe about these not existing
633 //$this->callAPISuccess('line_item', 'getsingle', array('contribution_id' => $contribution['id'], 'entity_id' => $membership['id']));
634 //renew it with processor setting completed - should extend membership
635 $submitParams['contact_id'] = $contribution['contact_id'];
636 $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 1, 'trxn_id' => 'create_second_success'));
637 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
638 $this->callAPISuccess('contribution', 'getsingle', array(
639 'id' => array('NOT IN' => array($contribution['id'])),
640 'contribution_page_id' => $this->_ids
['contribution_page'],
641 'contribution_status_id' => 1,
643 $renewedMembership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
644 $this->assertEquals(date('Y-m-d', strtotime('+ 1 year', strtotime($membership['end_date']))), $renewedMembership['end_date']);
645 $recurringContribution = $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $contribution['contribution_recur_id']));
646 $this->assertEquals(5, $recurringContribution['contribution_status_id']);
650 * Test submit recurring membership with immediate confirmation (IATS style).
652 * - we process 2 membership transactions against with a recurring contribution against a contribution page with an immediate
653 * processor (IATS style - denoted by returning trxn_id)
654 * - the first creates a new membership, completed contribution, in progress recurring. Check these
655 * - create another - end date should be extended
657 public function testSubmitMembershipPriceSetPaymentPaymentProcessorSeparatePaymentRecurInstantPayment() {
659 $this->setUpMembershipContributionPage(TRUE);
660 $dummyPP = Civi\Payment\System
::singleton()->getByProcessor($this->_paymentProcessor
);
661 $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 1, 'trxn_id' => 'create_first_success'));
663 $submitParams = array(
664 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
665 'id' => (int) $this->_ids
['contribution_page'],
667 'billing_first_name' => 'Billy',
668 'billing_middle_name' => 'Goat',
669 'billing_last_name' => 'Gruff',
670 'email' => 'billy@goat.gruff',
671 'selectMembership' => $this->_ids
['membership_type'],
672 'payment_processor_id' => 1,
673 'credit_card_number' => '4111111111111111',
674 'credit_card_type' => 'Visa',
675 'credit_card_exp_date' => array('M' => 9, 'Y' => 2040),
678 'auto_renew' => TRUE,
679 'frequency_interval' => 1,
680 'frequency_unit' => 'month',
683 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
684 $contribution = $this->callAPISuccess('contribution', 'get', array(
685 'contribution_page_id' => $this->_ids
['contribution_page'],
686 'contribution_status_id' => 1,
689 $this->assertEquals(2, $contribution['count']);
690 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
691 $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
692 $this->assertNotEmpty($contribution['values'][$membershipPayment['contribution_id']]['contribution_recur_id']);
693 $this->callAPISuccess('contribution_recur', 'getsingle', array());
697 * Test submit recurring membership with delayed confirmation (Authorize.net style)
698 * - we process 2 membership transactions against with a recurring contribution against a contribution page with a delayed
699 * processor (Authorize.net style - denoted by NOT returning trxn_id)
700 * - the first creates a pending membership, pending contribution, penging recurring. Check these
701 * - complete the transaction
702 * - create another - end date should NOT be extended
704 public function testSubmitMembershipPriceSetPaymentPaymentProcessorRecurDelayed() {
705 $this->params
['is_recur'] = 1;
706 $this->params
['recur_frequency_unit'] = 'month';
707 $this->setUpMembershipContributionPage();
708 $dummyPP = Civi\Payment\System
::singleton()->getByProcessor($this->_paymentProcessor
);
709 $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 2));
711 $submitParams = array(
712 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
713 'id' => (int) $this->_ids
['contribution_page'],
715 'billing_first_name' => 'Billy',
716 'billing_middle_name' => 'Goat',
717 'billing_last_name' => 'Gruff',
718 'email' => 'billy@goat.gruff',
719 'selectMembership' => $this->_ids
['membership_type'],
720 'payment_processor_id' => 1,
721 'credit_card_number' => '4111111111111111',
722 'credit_card_type' => 'Visa',
723 'credit_card_exp_date' => array('M' => 9, 'Y' => 2040),
726 'frequency_interval' => 1,
727 'frequency_unit' => 'month',
730 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
731 $contribution = $this->callAPISuccess('contribution', 'getsingle', array(
732 'contribution_page_id' => $this->_ids
['contribution_page'],
733 'contribution_status_id' => 2,
735 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
736 $this->assertEquals($membershipPayment['contribution_id'], $contribution['id']);
737 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
738 $this->assertEquals($membership['contact_id'], $contribution['contact_id']);
739 $this->assertEquals(5, $membership['status_id']);
740 //@todo - check with Joe about these not existing
741 //$this->callAPISuccess('line_item', 'getsingle', array('contribution_id' => $contribution['id'], 'entity_id' => $membership['id']));
742 $this->callAPISuccess('contribution', 'completetransaction', array(
743 'id' => $contribution['id'],
744 'trxn_id' => 'ipn_called',
745 'payment_processor_id' => $this->_paymentProcessor
['id'],
747 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
748 //renew it with processor setting completed - should extend membership
749 $submitParams = array_merge($submitParams, array(
750 'contact_id' => $contribution['contact_id'],
752 'frequency_interval' => 1,
753 'frequency_unit' => 'month',
756 $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 2));
757 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
758 $newContribution = $this->callAPISuccess('contribution', 'getsingle', array(
760 'NOT IN' => array($contribution['id']),
762 'contribution_page_id' => $this->_ids
['contribution_page'],
763 'contribution_status_id' => 2,
767 $renewedMembership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
768 //no renewal as the date hasn't changed
769 $this->assertEquals($membership['end_date'], $renewedMembership['end_date']);
770 $recurringContribution = $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $newContribution['contribution_recur_id']));
771 $this->assertEquals(2, $recurringContribution['contribution_status_id']);
775 * Set up membership contribution page.
776 * @param bool $isSeparatePayment
778 public function setUpMembershipContributionPage($isSeparatePayment = FALSE) {
779 $this->setUpMembershipBlockPriceSet();
780 $this->setupPaymentProcessor();
781 $this->setUpContributionPage();
783 $this->callAPISuccess('membership_block', 'create', array(
784 'entity_id' => $this->_ids
['contribution_page'],
785 'entity_table' => 'civicrm_contribution_page',
786 'is_required' => TRUE,
788 'is_separate_payment' => $isSeparatePayment,
789 'membership_type_default' => $this->_ids
['membership_type'],
794 * The default data set does not include a complete default membership price set - not quite sure why.
796 * This function ensures it exists & populates $this->_ids with it's data
798 public function setUpMembershipBlockPriceSet() {
799 $this->_ids
['price_set'][] = $this->callAPISuccess('price_set', 'getvalue', array(
800 'name' => 'default_membership_type_amount',
803 if (empty($this->_ids
['membership_type'])) {
804 $this->_ids
['membership_type'] = array($this->membershipTypeCreate(array('minimum_fee' => 2)));
806 $priceField = $this->callAPISuccess('price_field', 'create', array(
807 'price_set_id' => reset($this->_ids
['price_set']),
808 'name' => 'membership_amount',
809 'label' => 'Membership Amount',
810 'html_type' => 'Radio',
813 $this->_ids
['price_field'][] = $priceField['id'];
815 foreach ($this->_ids
['membership_type'] as $membershipTypeID) {
816 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
817 'name' => 'membership_amount',
818 'label' => 'Membership Amount',
820 'financial_type_id' => 'Donation',
821 'format.only_id' => TRUE,
822 'membership_type_id' => $membershipTypeID,
823 'price_field_id' => $priceField['id'],
825 $this->_ids
['price_field_value'][] = $priceFieldValue['id'];
830 * Add text field other amount to the price set.
832 public function addOtherAmountFieldToMembershipPriceSet() {
833 $this->_ids
['price_field']['other_amount'] = $this->callAPISuccess('price_field', 'create', array(
834 'price_set_id' => reset($this->_ids
['price_set']),
835 'name' => 'other_amount',
836 'label' => 'Other Amount',
837 'html_type' => 'Text',
838 'format.only_id' => TRUE,
841 $this->_ids
['price_field_value']['other_amount'] = $this->callAPISuccess('price_field_value', 'create', array(
842 'financial_type_id' => 'Donation',
843 'format.only_id' => TRUE,
844 'label' => 'Other Amount',
846 'price_field_id' => $this->_ids
['price_field']['other_amount'],
851 * Help function to set up contribution page with some defaults.
853 public function setUpContributionPage() {
854 $contributionPageResult = $this->callAPISuccess($this->_entity
, 'create', $this->params
);
855 if (empty($this->_ids
['price_set'])) {
856 $priceSet = $this->callAPISuccess('price_set', 'create', $this->_priceSetParams
);
857 $this->_ids
['price_set'][] = $priceSet['id'];
859 $priceSetID = reset($this->_ids
['price_set']);
860 CRM_Price_BAO_PriceSet
::addTo('civicrm_contribution_page', $contributionPageResult['id'], $priceSetID);
862 if (empty($this->_ids
['price_field'])) {
863 $priceField = $this->callAPISuccess('price_field', 'create', array(
864 'price_set_id' => $priceSetID,
865 'label' => 'Goat Breed',
866 'html_type' => 'Radio',
868 $this->_ids
['price_field'] = array($priceField['id']);
870 if (empty($this->_ids
['price_field_value'])) {
871 $this->callAPISuccess('price_field_value', 'create', array(
872 'price_set_id' => $priceSetID,
873 'price_field_id' => $priceField['id'],
874 'label' => 'Long Haired Goat',
875 'financial_type_id' => 'Donation',
877 'financial_type_id' => 'Donation',
880 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
881 'price_set_id' => $priceSetID,
882 'price_field_id' => $priceField['id'],
883 'label' => 'Shoe-eating Goat',
884 'financial_type_id' => 'Donation',
886 'financial_type_id' => 'Donation',
889 $this->_ids
['price_field_value'] = array($priceFieldValue['id']);
891 $this->_ids
['contribution_page'] = $contributionPageResult['id'];
894 public static function setUpBeforeClass() {
895 // put stuff here that should happen before all tests in this unit
898 public static function tearDownAfterClass() {
899 $tablesToTruncate = array(
901 'civicrm_financial_type',
902 'civicrm_contribution',
903 'civicrm_contribution_page',
905 $unitTest = new CiviUnitTestCase();
906 $unitTest->quickCleanup($tablesToTruncate);
910 * Create a payment processor instance.
912 protected function setupPaymentProcessor() {
913 $this->params
['payment_processor_id'] = $this->_ids
['payment_processor'] = $this->paymentProcessorCreate(array(
914 'payment_processor_type_id' => 'Dummy',
915 'class_name' => 'Payment_Dummy',
918 $this->_paymentProcessor
= $this->callAPISuccess('payment_processor', 'getsingle', array('id' => $this->params
['payment_processor_id']));