3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
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 +--------------------------------------------------------------------+
28 require_once 'CiviTest/CiviUnitTestCase.php';
29 require_once 'CiviTest/CiviMailUtils.php';
32 * Test APIv3 civicrm_contribute_recur* functions
34 * @package CiviCRM_APIv3
35 * @subpackage API_Contribution
37 class api_v3_ContributionPageTest
extends CiviUnitTestCase
{
38 protected $_apiversion = 3;
39 protected $testAmount = 34567;
42 protected $contactIds = array();
43 protected $_entity = 'contribution_page';
44 protected $contribution_result = NULL;
45 protected $_priceSetParams = array();
47 * Payment processor details.
50 protected $_paymentProcessor = array();
59 protected $_ids = array();
62 public $DBResetRequired = TRUE;
64 public function setUp() {
66 $this->contactIds
[] = $this->individualCreate();
67 $this->params
= array(
68 'title' => "Test Contribution Page",
69 'financial_type_id' => 1,
71 'goal_amount' => $this->testAmount
,
73 'is_monetary' => TRUE,
74 'is_email_receipt' => TRUE,
75 'receipt_from_email' => 'yourconscience@donate.com',
76 'receipt_from_name' => 'Ego Freud',
79 $this->_priceSetParams
= array(
80 'is_quick_config' => 1,
81 'extends' => 'CiviContribute',
82 'financial_type_id' => 'Donation',
87 public function tearDown() {
88 foreach ($this->contactIds
as $id) {
89 $this->callAPISuccess('contact', 'delete', array('id' => $id));
91 $this->quickCleanUpFinancialEntities();
94 public function testCreateContributionPage() {
95 $result = $this->callAPIAndDocument($this->_entity
, 'create', $this->params
, __FUNCTION__
, __FILE__
);
96 $this->assertEquals(1, $result['count']);
97 $this->assertNotNull($result['values'][$result['id']]['id']);
98 $this->getAndCheck($this->params
, $result['id'], $this->_entity
);
101 public function testGetBasicContributionPage() {
102 $createResult = $this->callAPISuccess($this->_entity
, 'create', $this->params
);
103 $this->id
= $createResult['id'];
106 'financial_type_id' => 1,
108 $getResult = $this->callAPIAndDocument($this->_entity
, 'get', $getParams, __FUNCTION__
, __FILE__
);
109 $this->assertEquals(1, $getResult['count']);
112 public function testGetContributionPageByAmount() {
113 $createResult = $this->callAPISuccess($this->_entity
, 'create', $this->params
);
114 $this->id
= $createResult['id'];
116 'amount' => '' . $this->testAmount
, // 3456
118 'financial_type_id' => 1,
120 $getResult = $this->callAPIAndDocument($this->_entity
, 'get', $getParams, __FUNCTION__
, __FILE__
);
121 $this->assertEquals(1, $getResult['count']);
124 public function testDeleteContributionPage() {
125 $createResult = $this->callAPISuccess($this->_entity
, 'create', $this->params
);
126 $deleteParams = array('id' => $createResult['id']);
127 $this->callAPIAndDocument($this->_entity
, 'delete', $deleteParams, __FUNCTION__
, __FILE__
);
128 $checkDeleted = $this->callAPISuccess($this->_entity
, 'get', array());
129 $this->assertEquals(0, $checkDeleted['count']);
132 public function testGetFieldsContributionPage() {
133 $result = $this->callAPISuccess($this->_entity
, 'getfields', array('action' => 'create'));
134 $this->assertEquals(12, $result['values']['start_date']['type']);
139 * Test form submission with basic price set.
141 public function testSubmit() {
142 $this->setUpContributionPage();
143 $priceFieldID = reset($this->_ids
['price_field']);
144 $priceFieldValueID = reset($this->_ids
['price_field_value']);
145 $submitParams = array(
146 'price_' . $priceFieldID => $priceFieldValueID,
147 'id' => (int) $this->_ids
['contribution_page'],
151 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
152 $this->callAPISuccess('contribution', 'getsingle', array('contribution_page_id' => $this->_ids
['contribution_page']));
156 * Test form submission with billing first & last name where the contact does NOT
157 * otherwise have one.
159 public function testSubmitNewBillingNameData() {
160 $this->setUpContributionPage();
161 $contact = $this->callAPISuccess('Contact', 'create', array('contact_type' => 'Individual', 'email' => 'wonderwoman@amazon.com'));
162 $priceFieldID = reset($this->_ids
['price_field']);
163 $priceFieldValueID = reset($this->_ids
['price_field_value']);
164 $submitParams = array(
165 'price_' . $priceFieldID => $priceFieldValueID,
166 'id' => (int) $this->_ids
['contribution_page'],
168 'billing_first_name' => 'Wonder',
169 'billing_last_name' => 'Woman',
170 'contactID' => $contact['id'],
171 'email' => 'wonderwoman@amazon.com',
174 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
175 $contact = $this->callAPISuccess('Contact', 'get', array(
176 'id' => $contact['id'],
184 $this->assertEquals(array(
185 'first_name' => 'Wonder',
186 'last_name' => 'Woman',
187 'display_name' => 'Wonder Woman',
188 'sort_name' => 'Woman, Wonder',
189 'id' => $contact['id'],
190 'contact_id' => $contact['id'],
191 ), $contact['values'][$contact['id']]);
196 * Test form submission with billing first & last name where the contact does
197 * otherwise have one and should not be overwritten.
199 public function testSubmitNewBillingNameDoNotOverwrite() {
200 $this->setUpContributionPage();
201 $contact = $this->callAPISuccess('Contact', 'create', array(
202 'contact_type' => 'Individual',
203 'email' => 'wonderwoman@amazon.com',
204 'first_name' => 'Super',
205 'last_name' => 'Boy',
207 $priceFieldID = reset($this->_ids
['price_field']);
208 $priceFieldValueID = reset($this->_ids
['price_field_value']);
209 $submitParams = array(
210 'price_' . $priceFieldID => $priceFieldValueID,
211 'id' => (int) $this->_ids
['contribution_page'],
213 'billing_first_name' => 'Wonder',
214 'billing_last_name' => 'Woman',
215 'contactID' => $contact['id'],
216 'email' => 'wonderwoman@amazon.com',
219 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
220 $contact = $this->callAPISuccess('Contact', 'get', array(
221 'id' => $contact['id'],
229 $this->assertEquals(array(
230 'first_name' => 'Super',
231 'last_name' => 'Boy',
232 'display_name' => 'Super Boy',
233 'sort_name' => 'Boy, Super',
234 'id' => $contact['id'],
235 'contact_id' => $contact['id'],
236 ), $contact['values'][$contact['id']]);
241 * Test process with instant payment when more than one configured for the page.
245 public function testSubmitRecurMultiProcessorInstantPayment() {
246 $this->setUpContributionPage();
247 $this->setupPaymentProcessor();
248 $paymentProcessor2ID = $this->paymentProcessorCreate(array(
249 'payment_processor_type_id' => 'Dummy',
250 'name' => 'processor 2',
251 'class_name' => 'Payment_Dummy',
254 $dummyPP = Civi\Payment\System
::singleton()->getById($paymentProcessor2ID);
255 $dummyPP->setDoDirectPaymentResult(array(
256 'payment_status_id' => 1,
257 'trxn_id' => 'create_first_success',
260 $this->callAPISuccess('ContributionPage', 'create', array(
261 'id' => $this->_ids
['contribution_page'],
262 'payment_processor' => array($paymentProcessor2ID, $this->_ids
['payment_processor']),
265 $priceFieldID = reset($this->_ids
['price_field']);
266 $priceFieldValueID = reset($this->_ids
['price_field_value']);
267 $submitParams = array(
268 'price_' . $priceFieldID => $priceFieldValueID,
269 'id' => (int) $this->_ids
['contribution_page'],
272 'frequency_interval' => 1,
273 'frequency_unit' => 'month',
274 'payment_processor_id' => $paymentProcessor2ID,
277 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
278 $contribution = $this->callAPISuccess('contribution', 'getsingle', array(
279 'contribution_page_id' => $this->_ids
['contribution_page'],
280 'contribution_status_id' => 1,
282 $this->assertEquals('create_first_success', $contribution['trxn_id']);
283 $this->assertEquals(10, $contribution['total_amount']);
284 $this->assertEquals(.85, $contribution['fee_amount']);
285 $this->assertEquals(9.15, $contribution['net_amount']);
289 * Test submit with a membership block in place.
291 public function testSubmitMembershipBlockNotSeparatePayment() {
292 $this->setUpMembershipContributionPage();
293 $submitParams = array(
294 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
295 'id' => (int) $this->_ids
['contribution_page'],
297 'billing_first_name' => 'Billy',
298 'billing_middle_name' => 'Goat',
299 'billing_last_name' => 'Gruff',
300 'selectMembership' => $this->_ids
['membership_type'],
304 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
305 $contribution = $this->callAPISuccess('contribution', 'getsingle', array('contribution_page_id' => $this->_ids
['contribution_page']));
306 $this->callAPISuccess('membership_payment', 'getsingle', array('contribution_id' => $contribution['id']));
310 * Test submit with a membership block in place.
312 public function testSubmitMembershipBlockNotSeparatePaymentWithEmail() {
313 $mut = new CiviMailUtils($this, TRUE);
314 $this->setUpMembershipContributionPage();
315 $this->addProfile('supporter_profile', $this->_ids
['contribution_page']);
317 $submitParams = array(
318 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
319 'id' => (int) $this->_ids
['contribution_page'],
321 'billing_first_name' => 'Billy',
322 'billing_middle_name' => 'Goat',
323 'billing_last_name' => 'Gruff',
324 'selectMembership' => $this->_ids
['membership_type'],
325 'email-Primary' => 'billy-goat@the-bridge.net',
326 'payment_processor_id' => $this->_paymentProcessor
['id'],
327 'credit_card_number' => '4111111111111111',
328 'credit_card_type' => 'Visa',
329 'credit_card_exp_date' => array('M' => 9, 'Y' => 2040),
333 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
334 $contribution = $this->callAPISuccess('contribution', 'getsingle', array('contribution_page_id' => $this->_ids
['contribution_page']));
335 $this->callAPISuccess('membership_payment', 'getsingle', array('contribution_id' => $contribution['id']));
336 $mut->checkMailLog(array(
337 'Membership Type: General',
340 $mut->clearMessages();
344 * Test submit with a membership block in place.
346 public function testSubmitMembershipBlockNotSeparatePaymentZeroDollarsWithEmail() {
347 $mut = new CiviMailUtils($this, TRUE);
348 $this->_ids
['membership_type'] = array($this->membershipTypeCreate(array('minimum_fee' => 0)));
349 $this->setUpMembershipContributionPage();
350 $this->addProfile('supporter_profile', $this->_ids
['contribution_page']);
352 $submitParams = array(
353 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
354 'id' => (int) $this->_ids
['contribution_page'],
356 'billing_first_name' => 'Billy',
357 'billing_middle_name' => 'Goat',
358 'billing_last_name' => 'Gruffier',
359 'selectMembership' => $this->_ids
['membership_type'],
360 'email-Primary' => 'billy-goat@the-new-bridge.net',
363 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
364 $contribution = $this->callAPISuccess('contribution', 'getsingle', array('contribution_page_id' => $this->_ids
['contribution_page']));
365 $this->callAPISuccess('membership_payment', 'getsingle', array('contribution_id' => $contribution['id']));
366 $mut->checkMailLog(array(
367 'Membership Type: General',
375 $mut->clearMessages(999);
379 * Test submit with a membership block in place.
381 public function testSubmitMembershipBlockIsSeparatePayment() {
382 $this->setUpMembershipContributionPage(TRUE);
383 $this->_ids
['membership_type'] = array($this->membershipTypeCreate(array('minimum_fee' => 2)));
384 $submitParams = array(
385 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
386 'id' => (int) $this->_ids
['contribution_page'],
388 'billing_first_name' => 'Billy',
389 'billing_middle_name' => 'Goat',
390 'billing_last_name' => 'Gruff',
391 'selectMembership' => $this->_ids
['membership_type'],
394 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
395 $contributions = $this->callAPISuccess('contribution', 'get', array('contribution_page_id' => $this->_ids
['contribution_page']));
396 $this->assertCount(2, $contributions['values']);
397 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
398 $this->assertTrue(in_array($membershipPayment['contribution_id'], array_keys($contributions['values'])));
399 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
400 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
404 * Test submit with a membership block in place.
406 public function testSubmitMembershipBlockIsSeparatePaymentWithEmail() {
407 $mut = new CiviMailUtils($this, TRUE);
408 $this->setUpMembershipContributionPage(TRUE);
409 $this->addProfile('supporter_profile', $this->_ids
['contribution_page']);
411 $submitParams = array(
412 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
413 'id' => (int) $this->_ids
['contribution_page'],
415 'billing_first_name' => 'Billy',
416 'billing_middle_name' => 'Goat',
417 'billing_last_name' => 'Gruff',
418 'selectMembership' => $this->_ids
['membership_type'],
419 'email-Primary' => 'billy-goat@the-bridge.net',
420 'payment_processor_id' => $this->_paymentProcessor
['id'],
421 'credit_card_number' => '4111111111111111',
422 'credit_card_type' => 'Visa',
423 'credit_card_exp_date' => array('M' => 9, 'Y' => 2040),
427 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
428 $contributions = $this->callAPISuccess('contribution', 'get', array('contribution_page_id' => $this->_ids
['contribution_page']));
429 $this->assertCount(2, $contributions['values']);
430 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
431 $this->assertTrue(in_array($membershipPayment['contribution_id'], array_keys($contributions['values'])));
432 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
433 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
434 $mut->checkAllMailLog(array(
439 $mut->clearMessages(999);
443 * Test submit with a membership block in place.
445 public function testSubmitMembershipBlockIsSeparatePaymentZeroDollarsPayLaterWithEmail() {
446 $mut = new CiviMailUtils($this, TRUE);
447 $this->_ids
['membership_type'] = array($this->membershipTypeCreate(array('minimum_fee' => 0)));
448 $this->setUpMembershipContributionPage(TRUE);
449 $this->addProfile('supporter_profile', $this->_ids
['contribution_page']);
451 $submitParams = array(
452 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
453 'id' => (int) $this->_ids
['contribution_page'],
455 'billing_first_name' => 'Billy',
456 'billing_middle_name' => 'Goat',
457 'billing_last_name' => 'Gruffalo',
458 'selectMembership' => $this->_ids
['membership_type'],
459 'payment_processor_id' => 0,
460 'email-Primary' => 'gruffalo@the-bridge.net',
463 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
464 $contributions = $this->callAPISuccess('contribution', 'get', array('contribution_page_id' => $this->_ids
['contribution_page']));
465 $this->assertCount(2, $contributions['values']);
466 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
467 $this->assertTrue(in_array($membershipPayment['contribution_id'], array_keys($contributions['values'])));
468 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
469 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
470 $mut->checkMailLog(array(
472 'General Membership: $ 0.00',
476 $mut->clearMessages();
480 * Test submit with a membership block in place.
482 public function testSubmitMembershipBlockTwoTypesIsSeparatePayment() {
483 $this->_ids
['membership_type'] = array($this->membershipTypeCreate(array('minimum_fee' => 6)));
484 $this->_ids
['membership_type'][] = $this->membershipTypeCreate(array('name' => 'Student', 'minimum_fee' => 50));
485 $this->setUpMembershipContributionPage(TRUE);
486 $submitParams = array(
487 'price_' . $this->_ids
['price_field'][0] => $this->_ids
['price_field_value'][1],
488 'id' => (int) $this->_ids
['contribution_page'],
490 'billing_first_name' => 'Billy',
491 'billing_middle_name' => 'Goat',
492 'billing_last_name' => 'Gruff',
493 'selectMembership' => $this->_ids
['membership_type'][1],
496 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
497 $contributions = $this->callAPISuccess('contribution', 'get', array('contribution_page_id' => $this->_ids
['contribution_page']));
498 $this->assertCount(2, $contributions['values']);
499 $ids = array_keys($contributions['values']);
500 $this->assertEquals('10.00', $contributions['values'][$ids[0]]['total_amount']);
501 $this->assertEquals('50.00', $contributions['values'][$ids[1]]['total_amount']);
502 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
503 $this->assertArrayHasKey($membershipPayment['contribution_id'], $contributions['values']);
504 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
505 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
509 * Test submit with a membership block in place.
511 * We are expecting a separate payment for the membership vs the contribution.
513 public function testSubmitMembershipBlockIsSeparatePaymentPaymentProcessorNow() {
514 $this->setUpMembershipContributionPage(TRUE);
515 $processor = Civi\Payment\System
::singleton()->getById($this->_paymentProcessor
['id']);
516 $processor->setDoDirectPaymentResult(array('fee_amount' => .72));
517 $submitParams = array(
518 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
519 'id' => (int) $this->_ids
['contribution_page'],
521 'billing_first_name' => 'Billy',
522 'billing_middle_name' => 'Goat',
523 'billing_last_name' => 'Gruff',
524 'selectMembership' => $this->_ids
['membership_type'],
525 'payment_processor_id' => $this->_paymentProcessor
['id'],
526 'credit_card_number' => '4111111111111111',
527 'credit_card_type' => 'Visa',
528 'credit_card_exp_date' => array('M' => 9, 'Y' => 2040),
532 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
533 $contributions = $this->callAPISuccess('contribution', 'get', array(
534 'contribution_page_id' => $this->_ids
['contribution_page'],
535 'contribution_status_id' => 1,
537 $this->assertCount(2, $contributions['values']);
538 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
539 $this->assertTrue(in_array($membershipPayment['contribution_id'], array_keys($contributions['values'])));
540 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
541 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
542 foreach ($contributions['values'] as $contribution) {
543 $this->assertEquals(.72, $contribution['fee_amount']);
544 $this->assertEquals($contribution['total_amount'] - .72, $contribution['net_amount']);
549 * Test that when a transaction fails the pending contribution remains.
551 * An activity should also be created. CRM-16417.
553 public function testSubmitPaymentProcessorFailure() {
554 $this->setUpContributionPage();
555 $this->setupPaymentProcessor();
556 $this->createLoggedInUser();
557 $priceFieldID = reset($this->_ids
['price_field']);
558 $priceFieldValueID = reset($this->_ids
['price_field_value']);
559 $submitParams = array(
560 'price_' . $priceFieldID => $priceFieldValueID,
561 'id' => (int) $this->_ids
['contribution_page'],
563 'payment_processor_id' => 1,
564 'credit_card_number' => '4111111111111111',
565 'credit_card_type' => 'Visa',
566 'credit_card_exp_date' => array('M' => 9, 'Y' => 2008),
570 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
571 $contribution = $this->callAPISuccessGetSingle('contribution', array(
572 'contribution_page_id' => $this->_ids
['contribution_page'],
573 'contribution_status_id' => 2,
576 $this->callAPISuccessGetSingle('activity', array(
577 'source_record_id' => $contribution['id'],
578 'activity_type_id' => 'Failed Payment',
584 * Test submit recurring membership with immediate confirmation (IATS style).
586 * - we process 2 membership transactions against with a recurring contribution against a contribution page with an immediate
587 * processor (IATS style - denoted by returning trxn_id)
588 * - the first creates a new membership, completed contribution, in progress recurring. Check these
589 * - create another - end date should be extended
591 public function testSubmitMembershipPriceSetPaymentPaymentProcessorRecurInstantPayment() {
592 $this->params
['is_recur'] = 1;
593 $this->params
['recur_frequency_unit'] = 'month';
594 $this->setUpMembershipContributionPage();
595 $dummyPP = Civi\Payment\System
::singleton()->getByProcessor($this->_paymentProcessor
);
596 $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 1, 'trxn_id' => 'create_first_success'));
598 $submitParams = array(
599 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
600 'id' => (int) $this->_ids
['contribution_page'],
602 'billing_first_name' => 'Billy',
603 'billing_middle_name' => 'Goat',
604 'billing_last_name' => 'Gruff',
605 'email' => 'billy@goat.gruff',
606 'selectMembership' => $this->_ids
['membership_type'],
607 'payment_processor_id' => 1,
608 'credit_card_number' => '4111111111111111',
609 'credit_card_type' => 'Visa',
610 'credit_card_exp_date' => array('M' => 9, 'Y' => 2040),
613 'frequency_interval' => 1,
614 'frequency_unit' => 'month',
617 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
618 $contribution = $this->callAPISuccess('contribution', 'getsingle', array(
619 'contribution_page_id' => $this->_ids
['contribution_page'],
620 'contribution_status_id' => 1,
623 $this->assertEquals('create_first_success', $contribution['trxn_id']);
624 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
625 $this->assertEquals($membershipPayment['contribution_id'], $contribution['id']);
626 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
627 $this->assertEquals($membership['contact_id'], $contribution['contact_id']);
628 $this->assertEquals(1, $membership['status_id']);
629 $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $contribution['contribution_recur_id']));
630 //@todo - check with Joe about these not existing
631 //$this->callAPISuccess('line_item', 'getsingle', array('contribution_id' => $contribution['id'], 'entity_id' => $membership['id']));
632 //renew it with processor setting completed - should extend membership
633 $submitParams['contact_id'] = $contribution['contact_id'];
634 $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 1, 'trxn_id' => 'create_second_success'));
635 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
636 $this->callAPISuccess('contribution', 'getsingle', array(
637 'id' => array('NOT IN' => array($contribution['id'])),
638 'contribution_page_id' => $this->_ids
['contribution_page'],
639 'contribution_status_id' => 1,
641 $renewedMembership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
642 $this->assertEquals(date('Y-m-d', strtotime('+ 1 year', strtotime($membership['end_date']))), $renewedMembership['end_date']);
643 $recurringContribution = $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $contribution['contribution_recur_id']));
644 $this->assertEquals(5, $recurringContribution['contribution_status_id']);
648 * Test submit recurring membership with immediate confirmation (IATS style).
650 * - we process 2 membership transactions against with a recurring contribution against a contribution page with an immediate
651 * processor (IATS style - denoted by returning trxn_id)
652 * - the first creates a new membership, completed contribution, in progress recurring. Check these
653 * - create another - end date should be extended
655 public function testSubmitMembershipPriceSetPaymentPaymentProcessorSeparatePaymentRecurInstantPayment() {
657 $this->setUpMembershipContributionPage(TRUE);
658 $dummyPP = Civi\Payment\System
::singleton()->getByProcessor($this->_paymentProcessor
);
659 $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 1, 'trxn_id' => 'create_first_success'));
661 $submitParams = array(
662 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
663 'id' => (int) $this->_ids
['contribution_page'],
665 'billing_first_name' => 'Billy',
666 'billing_middle_name' => 'Goat',
667 'billing_last_name' => 'Gruff',
668 'email' => 'billy@goat.gruff',
669 'selectMembership' => $this->_ids
['membership_type'],
670 'payment_processor_id' => 1,
671 'credit_card_number' => '4111111111111111',
672 'credit_card_type' => 'Visa',
673 'credit_card_exp_date' => array('M' => 9, 'Y' => 2040),
676 'auto_renew' => TRUE,
677 'frequency_interval' => 1,
678 'frequency_unit' => 'month',
681 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
682 $contribution = $this->callAPISuccess('contribution', 'get', array(
683 'contribution_page_id' => $this->_ids
['contribution_page'],
684 'contribution_status_id' => 1,
687 $this->assertEquals(2, $contribution['count']);
688 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
689 $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
690 $this->assertNotEmpty($contribution['values'][$membershipPayment['contribution_id']]['contribution_recur_id']);
691 $this->callAPISuccess('contribution_recur', 'getsingle', array());
695 * Test submit recurring membership with delayed confirmation (Authorize.net style)
696 * - we process 2 membership transactions against with a recurring contribution against a contribution page with a delayed
697 * processor (Authorize.net style - denoted by NOT returning trxn_id)
698 * - the first creates a pending membership, pending contribution, penging recurring. Check these
699 * - complete the transaction
700 * - create another - end date should NOT be extended
702 public function testSubmitMembershipPriceSetPaymentPaymentProcessorRecurDelayed() {
703 $this->params
['is_recur'] = 1;
704 $this->params
['recur_frequency_unit'] = 'month';
705 $this->setUpMembershipContributionPage();
706 $dummyPP = Civi\Payment\System
::singleton()->getByProcessor($this->_paymentProcessor
);
707 $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 2));
709 $submitParams = array(
710 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
711 'id' => (int) $this->_ids
['contribution_page'],
713 'billing_first_name' => 'Billy',
714 'billing_middle_name' => 'Goat',
715 'billing_last_name' => 'Gruff',
716 'email' => 'billy@goat.gruff',
717 'selectMembership' => $this->_ids
['membership_type'],
718 'payment_processor_id' => 1,
719 'credit_card_number' => '4111111111111111',
720 'credit_card_type' => 'Visa',
721 'credit_card_exp_date' => array('M' => 9, 'Y' => 2040),
724 'frequency_interval' => 1,
725 'frequency_unit' => 'month',
728 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL);
729 $contribution = $this->callAPISuccess('contribution', 'getsingle', array(
730 'contribution_page_id' => $this->_ids
['contribution_page'],
731 'contribution_status_id' => 2,
733 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
734 $this->assertEquals($membershipPayment['contribution_id'], $contribution['id']);
735 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
736 $this->assertEquals($membership['contact_id'], $contribution['contact_id']);
737 $this->assertEquals(5, $membership['status_id']);
738 //@todo - check with Joe about these not existing
739 //$this->callAPISuccess('line_item', 'getsingle', array('contribution_id' => $contribution['id'], 'entity_id' => $membership['id']));
740 $this->callAPISuccess('contribution', 'completetransaction', array(
741 'id' => $contribution['id'],
742 'trxn_id' => 'ipn_called',
743 'payment_processor_id' => $this->_paymentProcessor
['id'],
745 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
746 //renew it with processor setting completed - should extend membership
747 $submitParams = array_merge($submitParams, array(
748 'contact_id' => $contribution['contact_id'],
750 'frequency_interval' => 1,
751 'frequency_unit' => 'month',
754 $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 2));
755 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
756 $newContribution = $this->callAPISuccess('contribution', 'getsingle', array(
758 'NOT IN' => array($contribution['id']),
760 'contribution_page_id' => $this->_ids
['contribution_page'],
761 'contribution_status_id' => 2,
765 $renewedMembership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
766 //no renewal as the date hasn't changed
767 $this->assertEquals($membership['end_date'], $renewedMembership['end_date']);
768 $recurringContribution = $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $newContribution['contribution_recur_id']));
769 $this->assertEquals(2, $recurringContribution['contribution_status_id']);
773 * Set up membership contribution page.
774 * @param bool $isSeparatePayment
776 public function setUpMembershipContributionPage($isSeparatePayment = FALSE) {
777 $this->setUpMembershipBlockPriceSet();
778 $this->setupPaymentProcessor();
779 $this->setUpContributionPage();
781 $this->callAPISuccess('membership_block', 'create', array(
782 'entity_id' => $this->_ids
['contribution_page'],
783 'entity_table' => 'civicrm_contribution_page',
784 'is_required' => TRUE,
786 'is_separate_payment' => $isSeparatePayment,
787 'membership_type_default' => $this->_ids
['membership_type'],
792 * The default data set does not include a complete default membership price set - not quite sure why.
794 * This function ensures it exists & populates $this->_ids with it's data
796 public function setUpMembershipBlockPriceSet() {
797 $this->_ids
['price_set'][] = $this->callAPISuccess('price_set', 'getvalue', array(
798 'name' => 'default_membership_type_amount',
801 if (empty($this->_ids
['membership_type'])) {
802 $this->_ids
['membership_type'] = array($this->membershipTypeCreate(array('minimum_fee' => 2)));
804 $priceField = $this->callAPISuccess('price_field', 'create', array(
805 'price_set_id' => reset($this->_ids
['price_set']),
806 'name' => 'membership_amount',
807 'label' => 'Membership Amount',
808 'html_type' => 'Radio',
811 $this->_ids
['price_field'][] = $priceField['id'];
813 foreach ($this->_ids
['membership_type'] as $membershipTypeID) {
814 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
815 'name' => 'membership_amount',
816 'label' => 'Membership Amount',
818 'financial_type_id' => 'Donation',
819 'format.only_id' => TRUE,
820 'membership_type_id' => $membershipTypeID,
821 'price_field_id' => $priceField['id'],
823 $this->_ids
['price_field_value'][] = $priceFieldValue['id'];
828 * Add text field other amount to the price set.
830 public function addOtherAmountFieldToMembershipPriceSet() {
831 $this->_ids
['price_field']['other_amount'] = $this->callAPISuccess('price_field', 'create', array(
832 'price_set_id' => reset($this->_ids
['price_set']),
833 'name' => 'other_amount',
834 'label' => 'Other Amount',
835 'html_type' => 'Text',
836 'format.only_id' => TRUE,
839 $this->_ids
['price_field_value']['other_amount'] = $this->callAPISuccess('price_field_value', 'create', array(
840 'financial_type_id' => 'Donation',
841 'format.only_id' => TRUE,
842 'label' => 'Other Amount',
844 'price_field_id' => $this->_ids
['price_field']['other_amount'],
849 * Help function to set up contribution page with some defaults.
851 public function setUpContributionPage() {
852 $contributionPageResult = $this->callAPISuccess($this->_entity
, 'create', $this->params
);
853 if (empty($this->_ids
['price_set'])) {
854 $priceSet = $this->callAPISuccess('price_set', 'create', $this->_priceSetParams
);
855 $this->_ids
['price_set'][] = $priceSet['id'];
857 $priceSetID = reset($this->_ids
['price_set']);
858 CRM_Price_BAO_PriceSet
::addTo('civicrm_contribution_page', $contributionPageResult['id'], $priceSetID);
860 if (empty($this->_ids
['price_field'])) {
861 $priceField = $this->callAPISuccess('price_field', 'create', array(
862 'price_set_id' => $priceSetID,
863 'label' => 'Goat Breed',
864 'html_type' => 'Radio',
866 $this->_ids
['price_field'] = array($priceField['id']);
868 if (empty($this->_ids
['price_field_value'])) {
869 $this->callAPISuccess('price_field_value', 'create', array(
870 'price_set_id' => $priceSetID,
871 'price_field_id' => $priceField['id'],
872 'label' => 'Long Haired Goat',
873 'financial_type_id' => 'Donation',
875 'financial_type_id' => 'Donation',
878 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
879 'price_set_id' => $priceSetID,
880 'price_field_id' => $priceField['id'],
881 'label' => 'Shoe-eating Goat',
882 'financial_type_id' => 'Donation',
884 'financial_type_id' => 'Donation',
887 $this->_ids
['price_field_value'] = array($priceFieldValue['id']);
889 $this->_ids
['contribution_page'] = $contributionPageResult['id'];
892 public static function setUpBeforeClass() {
893 // put stuff here that should happen before all tests in this unit
896 public static function tearDownAfterClass() {
897 $tablesToTruncate = array(
899 'civicrm_financial_type',
900 'civicrm_contribution',
901 'civicrm_contribution_page',
903 $unitTest = new CiviUnitTestCase();
904 $unitTest->quickCleanup($tablesToTruncate);
908 * Create a payment processor instance.
910 protected function setupPaymentProcessor() {
911 $this->params
['payment_processor_id'] = $this->_ids
['payment_processor'] = $this->paymentProcessorCreate(array(
912 'payment_processor_type_id' => 'Dummy',
913 'class_name' => 'Payment_Dummy',
916 $this->_paymentProcessor
= $this->callAPISuccess('payment_processor', 'getsingle', array('id' => $this->params
['payment_processor_id']));