3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
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';
32 * Test APIv3 civicrm_contribute_recur* functions
34 * @package CiviCRM_APIv3
35 * @subpackage API_Contribution
38 class api_v3_ContributionPageTest
extends CiviUnitTestCase
{
39 protected $_apiversion = 3;
40 protected $testAmount = 34567;
43 protected $contactIds = array();
44 protected $_entity = 'contribution_page';
45 protected $contribution_result = null;
46 protected $_priceSetParams = array();
48 * Payment processor details
51 protected $_paymentProcessor = array();
60 protected $_ids = array();
63 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,
76 $this->_priceSetParams
= array(
77 'is_quick_config' => 1,
78 'extends' => 'CiviContribute',
79 'financial_type_id' => 'Donation',
85 foreach ($this->contactIds
as $id) {
86 $this->callAPISuccess('contact', 'delete', array('id' => $id));
88 $this->quickCleanUpFinancialEntities();
91 public function testCreateContributionPage() {
92 $result = $this->callAPIAndDocument($this->_entity
, 'create', $this->params
, __FUNCTION__
, __FILE__
);
93 $this->assertEquals(1, $result['count']);
94 $this->assertNotNull($result['values'][$result['id']]['id']);
95 $this->getAndCheck($this->params
, $result['id'], $this->_entity
);
98 public function testGetBasicContributionPage() {
99 $createResult = $this->callAPISuccess($this->_entity
, 'create', $this->params
);
100 $this->id
= $createResult['id'];
103 'financial_type_id' => 1,
105 $getResult = $this->callAPIAndDocument($this->_entity
, 'get', $getParams, __FUNCTION__
, __FILE__
);
106 $this->assertEquals(1, $getResult['count']);
109 public function testGetContributionPageByAmount() {
110 $createResult = $this->callAPISuccess($this->_entity
, 'create', $this->params
);
111 $this->id
= $createResult['id'];
113 'amount' => ''. $this->testAmount
, // 3456
115 'financial_type_id' => 1,
117 $getResult = $this->callAPIAndDocument($this->_entity
, 'get', $getParams, __FUNCTION__
, __FILE__
);
118 $this->assertEquals(1, $getResult['count']);
121 public function testDeleteContributionPage() {
122 $createResult = $this->callAPISuccess($this->_entity
, 'create', $this->params
);
123 $deleteParams = array('id' => $createResult['id']);
124 $this->callAPIAndDocument($this->_entity
, 'delete', $deleteParams, __FUNCTION__
, __FILE__
);
125 $checkDeleted = $this->callAPISuccess($this->_entity
, 'get', array());
126 $this->assertEquals(0, $checkDeleted['count']);
129 public function testGetFieldsContributionPage() {
130 $result = $this->callAPISuccess($this->_entity
, 'getfields', array('action' => 'create'));
131 $this->assertEquals(12, $result['values']['start_date']['type']);
136 * Test form submission with basic price set
138 public function testSubmit() {
139 $this->setUpContributionPage();
140 $priceFieldID = reset($this->_ids
['price_field']);
141 $priceFieldValueID = reset($this->_ids
['price_field_value']);
142 $submitParams = array(
143 'price_' . $priceFieldID => $priceFieldValueID,
144 'id' => (int) $this->_ids
['contribution_page'],
148 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
149 $this->callAPISuccess('contribution', 'getsingle', array('contribution_page_id' => $this->_ids
['contribution_page']));
152 * Test submit with a membership block in place
154 public function testSubmitMembershipBlockNotSeparatePayment() {
155 $this->setUpMembershipContributionPage();
156 $submitParams = array(
157 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
158 'id' => (int) $this->_ids
['contribution_page'],
160 'billing_first_name' => 'Billy',
161 'billing_middle_name' => 'Goat',
162 'billing_last_name' => 'Gruff',
163 'selectMembership' => $this->_ids
['membership_type'],
167 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL, 'Submit');
168 $contribution = $this->callAPISuccess('contribution', 'getsingle', array('contribution_page_id' => $this->_ids
['contribution_page']));
169 $this->callAPISuccess('membership_payment', 'getsingle', array('contribution_id' => $contribution['id']));
173 * Test submit with a membership block in place
175 public function testSubmitMembershipBlockIsSeparatePayment() {
176 $this->setUpMembershipContributionPage(TRUE);
177 $submitParams = array(
178 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
179 'id' => (int) $this->_ids
['contribution_page'],
181 'billing_first_name' => 'Billy',
182 'billing_middle_name' => 'Goat',
183 'billing_last_name' => 'Gruff',
184 'selectMembership' => $this->_ids
['membership_type'],
187 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL, 'Submit');
188 $contributions = $this->callAPISuccess('contribution', 'get', array('contribution_page_id' => $this->_ids
['contribution_page']));
189 $this->assertCount(2, $contributions['values']);
190 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
191 $this->assertTrue(in_array($membershipPayment['contribution_id'], array_keys($contributions['values'])));
192 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
193 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
197 * Test submit with a membership block in place
199 public function testSubmitMembershipBlockTwoTypesIsSeparatePayment() {
200 $this->_ids
['membership_type'] = array($this->membershipTypeCreate(array('minimum_fee' => 6)));
201 $this->_ids
['membership_type'][] = $this->membershipTypeCreate(array('name' => 'Student', 'minimum_fee' => 50));
202 $this->setUpMembershipContributionPage(TRUE);
203 $submitParams = array(
204 'price_' . $this->_ids
['price_field'][0] => $this->_ids
['price_field_value'][1],
205 'id' => (int) $this->_ids
['contribution_page'],
207 'billing_first_name' => 'Billy',
208 'billing_middle_name' => 'Goat',
209 'billing_last_name' => 'Gruff',
210 'selectMembership' => $this->_ids
['membership_type'][1],
213 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL, 'Submit');
214 $contributions = $this->callAPISuccess('contribution', 'get', array('contribution_page_id' => $this->_ids
['contribution_page'],));
215 $this->assertCount(2, $contributions['values']);
216 $ids = array_keys($contributions['values']);
217 $this->assertEquals('10.00', $contributions['values'][$ids[0]]['total_amount']);
218 $this->assertEquals('50.00', $contributions['values'][$ids[1]]['total_amount']);
219 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
220 $this->assertArrayHasKey($membershipPayment['contribution_id'], $contributions['values']);
221 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
222 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
226 * Test submit with a membership block in place
228 public function testSubmitMembershipBlockIsSeparatePaymentPaymentProcessor() {
229 $this->setUpMembershipContributionPage(TRUE);
230 $submitParams = array(
231 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
232 'id' => (int) $this->_ids
['contribution_page'],
234 'billing_first_name' => 'Billy',
235 'billing_middle_name' => 'Goat',
236 'billing_last_name' => 'Gruff',
237 'selectMembership' => $this->_ids
['membership_type'],
238 'payment_processor' => 1,
239 'credit_card_number' => '4111111111111111',
240 'credit_card_type' => 'Visa',
241 'credit_card_exp_date' => array('M' => 9, 'Y' => 2040 ),
245 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL, 'Submit');
246 $contributions = $this->callAPISuccess('contribution', 'get', array('contribution_page_id' => $this->_ids
['contribution_page'], 'contribution_status_id' => 1));
247 $this->assertCount(2, $contributions['values']);
248 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
249 $this->assertTrue(in_array($membershipPayment['contribution_id'], array_keys($contributions['values'])));
250 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
251 $this->assertEquals($membership['contact_id'], $contributions['values'][$membershipPayment['contribution_id']]['contact_id']);
255 * Test submit with a membership block in place
257 public function testSubmitMembershipPriceSetPaymentPaymentProcessorRecur() {
258 $this->params
['is_recur'] = 1;
260 $this->params
['recur_frequency_unit'] = 'month';
261 $this->setUpMembershipContributionPage();
262 $dummyPP = CRM_Core_Payment
::singleton('live', $this->_paymentProcessor
);
263 $dummyPP->setDoDirectPaymentResult(array('contribution_status_id' => 1, 'trxn_id' => 1233,));
265 $submitParams = array(
266 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
267 'id' => (int) $this->_ids
['contribution_page'],
269 'billing_first_name' => 'Billy',
270 'billing_middle_name' => 'Goat',
271 'billing_last_name' => 'Gruff',
272 'email' => 'billy@goat.gruff',
273 'selectMembership' => $this->_ids
['membership_type'],
274 'payment_processor' => 1,
275 'credit_card_number' => '4111111111111111',
276 'credit_card_type' => 'Visa',
277 'credit_card_exp_date' => array('M' => 9, 'Y' => 2040 ),
280 'frequency_interval' => 1,
281 'frequency_unit' => 'month',
284 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL, 'Submit');
285 $contribution = $this->callAPISuccess('contribution', 'getsingle', array('contribution_page_id' => $this->_ids
['contribution_page'], 'contribution_status_id' => 1));
286 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
287 $this->assertEquals($membershipPayment['contribution_id'], $contribution['id']);
288 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
289 $this->assertEquals($membership['contact_id'], $contribution['contact_id']);
290 $this->assertEquals(1, $membership['status_id']);
291 $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $contribution['contribution_recur_id']));
293 //renew it with processor setting completed - should extend membership
294 $submitParams['contact_id'] = $contribution['contact_id'];
295 $dummyPP->setDoDirectPaymentResult(array('contribution_status_id' => 1, 'trxn_id' => 1234,));
296 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
297 $this->callAPISuccess('contribution', 'getsingle', array('id' => array('NOT IN' => array($contribution['id'])), 'contribution_page_id' => $this->_ids
['contribution_page'], 'contribution_status_id' => 1));
298 $renewedMembership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
299 $this->assertEquals(date('Y-m-d', strtotime('+ 1 year', strtotime($membership['end_date']))), $renewedMembership['end_date']);
300 $recurringContribution = $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $contribution['contribution_recur_id']));
301 //@todo this assertion should pass
302 //$this->assertEquals(5, $recurringContribution['contribution_status_id']);
306 * Test submit with a membership block in place
308 public function testSubmitMembershipPriceSetPaymentPaymentProcessorRecurDelayed() {
309 $this->params
['is_recur'] = 1;
311 $this->params
['recur_frequency_unit'] = 'month';
312 $this->setUpMembershipContributionPage();
313 $dummyPP = CRM_Core_Payment
::singleton('live', $this->_paymentProcessor
);
314 $dummyPP->setDoDirectPaymentResult(array('contribution_status_id' => 1, 'trxn_id' => 1233,));
316 $submitParams = array(
317 'price_' . $this->_ids
['price_field'][0] => reset($this->_ids
['price_field_value']),
318 'id' => (int) $this->_ids
['contribution_page'],
320 'billing_first_name' => 'Billy',
321 'billing_middle_name' => 'Goat',
322 'billing_last_name' => 'Gruff',
323 'email' => 'billy@goat.gruff',
324 'selectMembership' => $this->_ids
['membership_type'],
325 'payment_processor' => 1,
326 'credit_card_number' => '4111111111111111',
327 'credit_card_type' => 'Visa',
328 'credit_card_exp_date' => array('M' => 9, 'Y' => 2040 ),
332 $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__
, __FILE__
, 'submit contribution page', NULL, 'Submit');
333 $contribution = $this->callAPISuccess('contribution', 'getsingle', array('contribution_page_id' => $this->_ids
['contribution_page'], 'contribution_status_id' => 1));
334 $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
335 $this->assertEquals($membershipPayment['contribution_id'], $contribution['id']);
336 $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
337 $this->assertEquals($membership['contact_id'], $contribution['contact_id']);
338 $this->assertEquals(1, $membership['status_id']);
340 //renew it with processor setting completed - should extend membership
341 $submitParams = array_merge($submitParams, array(
342 'contact_id' => $contribution['contact_id'],
344 'frequency_interval' => 1,
345 'frequency_unit' => 'month',)
347 $dummyPP->setDoDirectPaymentResult(array('contribution_status_id' => 2,));
348 $this->markTestIncomplete('currently failing - this needs fixing per CRM-15296 as it shows that renewals are being actioned even when payment is not');
349 $this->callAPISuccess('contribution_page', 'submit', $submitParams);
350 $this->callAPISuccess('contribution', 'getsingle', array('id' => array(
351 'NOT IN' => array($contribution['id'])), 'contribution_page_id' => $this->_ids
['contribution_page'], 'contribution_status_id' => 2)
353 $renewedMembership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
354 //no renewal as the date hasn't changed
355 $this->assertEquals($membership['end_date'], $renewedMembership['end_date']);
356 $recurringContribution = $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $contribution['contribution_recur_id']));
357 $this->assertEquals(5, $recurringContribution['status_id']);
361 * set up membership contribution page
362 * @param bool $isSeparatePayment
364 function setUpMembershipContributionPage($isSeparatePayment = FALSE) {
365 $this->setUpMembershipBlockPriceSet();
366 $this->params
['payment_processor_id'] = $this->_ids
['payment_processor'] = $this->paymentProcessorCreate(array(
367 'payment_processor_type_id' => 'Dummy',
368 'class_name' => 'Payment_Dummy',
371 $this->_paymentProcessor
= $this->callAPISuccess('payment_processor', 'getsingle', array('id' => $this->params
['payment_processor_id']));
372 $this->setUpContributionPage();
374 $this->callAPISuccess('membership_block', 'create', array(
375 'entity_id' => $this->_ids
['contribution_page'],
376 'entity_table' => 'civicrm_contribution_page',
377 'is_required' => TRUE,
379 'is_separate_payment' => $isSeparatePayment,
380 'membership_type_default' => $this->_ids
['membership_type'],
385 * The default data set does not include a complete default membership price set - not quite sure why
386 * This function ensures it exists & populates $this->_ids with it's data
388 function setUpMembershipBlockPriceSet() {
389 $this->_ids
['price_set'][] = $this->callAPISuccess('price_set', 'getvalue', array('name' => 'default_membership_type_amount', 'return' => 'id'));
390 if (empty($this->_ids
['membership_type'])) {
391 $this->_ids
['membership_type'] = array($this->membershipTypeCreate(array('minimum_fee' => 2)));
393 $priceField = $this->callAPISuccess('price_field', 'create', array(
394 'price_set_id' => reset($this->_ids
['price_set']),
395 'name' => 'membership_amount',
396 'label' => 'Membership Amount',
397 'html_type' => 'Radio',
400 $this->_ids
['price_field'][] = $priceField['id'];
401 foreach ($this->_ids
['membership_type'] as $membershipTypeID) {
402 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
403 'name' => 'membership_amount',
404 'label' => 'Membership Amount',
406 'financial_type_id' => 1,
407 'format.only_id' => TRUE,
408 'membership_type_id' => $membershipTypeID,
409 'price_field_id' => $priceField['id'],
411 $this->_ids
['price_field_value'][] = $priceFieldValue['id'];
416 * help function to set up contribution page with some defaults
418 function setUpContributionPage() {
419 $contributionPageResult = $this->callAPISuccess($this->_entity
, 'create', $this->params
);
420 if (empty($this->_ids
['price_set'])) {
421 $priceSet = $this->callAPISuccess('price_set', 'create', $this->_priceSetParams
);
422 $this->_ids
['price_set'][] = $priceSet['id'];
424 $priceSetID = reset($this->_ids
['price_set']);
425 CRM_Price_BAO_PriceSet
::addTo('civicrm_contribution_page', $contributionPageResult['id'], $priceSetID );
427 if (empty($this->_ids
['price_field'])) {
428 $priceField = $this->callAPISuccess('price_field', 'create', array(
429 'price_set_id' => $priceSetID,
430 'label' => 'Goat Breed',
431 'html_type' => 'Radio',
433 $this->_ids
['price_field'] = array($priceField['id']);
435 if (empty($this->_ids
['price_field_value'])) {
436 $this->callAPISuccess('price_field_value', 'create', array(
437 'price_set_id' => $priceSetID,
438 'price_field_id' => $priceField['id'],
439 'label' => 'Long Haired Goat',
443 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
444 'price_set_id' => $priceSetID,
445 'price_field_id' => $priceField['id'],
446 'label' => 'Shoe-eating Goat',
450 $this->_ids
['price_field_value'] = array($priceFieldValue['id']);
452 $this->_ids
['contribution_page'] = $contributionPageResult['id'];
455 public static function setUpBeforeClass() {
456 // put stuff here that should happen before all tests in this unit
459 public static function tearDownAfterClass(){
460 $tablesToTruncate = array(
462 'civicrm_financial_type',
463 'civicrm_contribution',
464 'civicrm_contribution_page',
466 $unitTest = new CiviUnitTestCase();
467 $unitTest->quickCleanup($tablesToTruncate);