Merge remote-tracking branch 'upstream/4.6' into 4.6-master-2015-10-26-14-28-29
[civicrm-core.git] / tests / phpunit / CRM / Member / Form / MembershipTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
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. |
13 | |
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. |
18 | |
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 +--------------------------------------------------------------------+
26 */
27
28 /**
29 * File for the MembershipTest class
30 *
31 * (PHP 5)
32 *
33 * @author Walt Haas <walt@dharmatech.org> (801) 534-1262
34 */
35
36 /**
37 * Include class definitions
38 */
39 require_once 'CiviTest/CiviUnitTestCase.php';
40
41 require_once 'HTML/QuickForm/Page.php';
42
43 /**
44 * Test CRM_Member_Form_Membership functions.
45 *
46 * @package CiviCRM
47 */
48 class CRM_Member_Form_MembershipTest extends CiviUnitTestCase {
49
50 /**
51 * Assume empty database with just civicrm_data.
52 */
53 protected $_individualId;
54 protected $_contribution;
55 protected $_financialTypeId = 1;
56 protected $_apiversion;
57 protected $_entity = 'Membership';
58 protected $_params;
59 protected $_ids = array();
60 protected $_paymentProcessorID;
61
62 /**
63 * Membership type ID for annual fixed membership.
64 *
65 * @var int
66 */
67 protected $membershipTypeAnnualFixedID;
68
69 /**
70 * Parameters to create payment processor.
71 *
72 * @var array
73 */
74 protected $_processorParams = array();
75
76 /**
77 * ID of created membership.
78 *
79 * @var int
80 */
81 protected $_membershipID;
82
83 /**
84 * Payment instrument mapping.
85 *
86 * @var array
87 */
88 protected $paymentInstruments = array();
89
90 /**
91 * Test setup for every test.
92 *
93 * Connect to the database, truncate the tables that will be used
94 * and redirect stdin to a temporary file.
95 */
96 public function setUp() {
97 $this->_apiversion = 3;
98 parent::setUp();
99
100 $this->_individualId = $this->individualCreate();
101 $this->_paymentProcessorID = $this->processorCreate();
102 // Insert test data.
103 $op = new PHPUnit_Extensions_Database_Operation_Insert();
104 $op->execute($this->_dbconn,
105 $this->createFlatXMLDataSet(
106 dirname(__FILE__) . '/dataset/data.xml'
107 )
108 );
109 $membershipTypeAnnualFixed = $this->callAPISuccess('membership_type', 'create', array(
110 'domain_id' => 1,
111 'name' => "AnnualFixed",
112 'member_of_contact_id' => 23,
113 'duration_unit' => "year",
114 'duration_interval' => 1,
115 'period_type' => "fixed",
116 'fixed_period_start_day' => "101",
117 'fixed_period_rollover_day' => "1231",
118 'relationship_type_id' => 20,
119 'financial_type_id' => 2,
120 ));
121 $this->membershipTypeAnnualFixedID = $membershipTypeAnnualFixed['id'];
122
123 $instruments = $this->callAPISuccess('contribution', 'getoptions', array('field' => 'payment_instrument_id'));
124 $this->paymentInstruments = $instruments['values'];
125 }
126
127 /**
128 * Clean up after each test.
129 */
130 public function tearDown() {
131 $this->quickCleanUpFinancialEntities();
132 $this->quickCleanup(
133 array(
134 'civicrm_relationship',
135 'civicrm_membership_type',
136 'civicrm_membership',
137 'civicrm_uf_match',
138 )
139 );
140 $this->callAPISuccess('contact', 'delete', array('id' => 17, 'skip_undelete' => TRUE));
141 $this->callAPISuccess('contact', 'delete', array('id' => 23, 'skip_undelete' => TRUE));
142 $this->callAPISuccess('relationship_type', 'delete', array('id' => 20));
143 }
144
145 /**
146 * Test CRM_Member_Form_Membership::buildQuickForm()
147 */
148 //function testCRMMemberFormMembershipBuildQuickForm()
149 //{
150 // throw new PHPUnit_Framework_IncompleteTestError( "not implemented" );
151 //}
152
153 /**
154 * Test CRM_Member_Form_Membership::formRule() with a parameter
155 * that has an empty contact_select_id value
156 */
157 public function testFormRuleEmptyContact() {
158 $params = array(
159 'contact_select_id' => 0,
160 'membership_type_id' => array(1 => NULL),
161 );
162 $files = array();
163 $obj = new CRM_Member_Form_Membership();
164 $rc = $obj->formRule($params, $files, $obj);
165 $this->assertType('array', $rc);
166 $this->assertTrue(array_key_exists('membership_type_id', $rc));
167
168 $params['membership_type_id'] = array(1 => 3);
169 $rc = $obj->formRule($params, $files, $obj);
170 $this->assertType('array', $rc);
171 $this->assertTrue(array_key_exists('join_date', $rc));
172 }
173
174 /**
175 * Test that form rule fails if start date is before join date.
176 *
177 * Test CRM_Member_Form_Membership::formRule() with a parameter
178 * that has an start date before the join date and a rolling
179 * membership type.
180 */
181 public function testFormRuleRollingEarlyStart() {
182 $unixNow = time();
183 $ymdNow = date('m/d/Y', $unixNow);
184 $unixYesterday = $unixNow - (24 * 60 * 60);
185 $ymdYesterday = date('m/d/Y', $unixYesterday);
186 $params = array(
187 'join_date' => $ymdNow,
188 'start_date' => $ymdYesterday,
189 'end_date' => '',
190 'membership_type_id' => array('23', '15'),
191 );
192 $files = array();
193 $obj = new CRM_Member_Form_Membership();
194 $rc = call_user_func(array('CRM_Member_Form_Membership', 'formRule'),
195 $params, $files, $obj
196 );
197 $this->assertType('array', $rc);
198 $this->assertTrue(array_key_exists('start_date', $rc));
199 }
200
201 /**
202 * Test CRM_Member_Form_Membership::formRule() with a parameter
203 * that has an end date before the start date and a rolling
204 * membership type
205 */
206 public function testFormRuleRollingEarlyEnd() {
207 $unixNow = time();
208 $ymdNow = date('m/d/Y', $unixNow);
209 $unixYesterday = $unixNow - (24 * 60 * 60);
210 $ymdYesterday = date('m/d/Y', $unixYesterday);
211 $params = array(
212 'join_date' => $ymdNow,
213 'start_date' => $ymdNow,
214 'end_date' => $ymdYesterday,
215 'membership_type_id' => array('23', '15'),
216 );
217 $files = array();
218 $obj = new CRM_Member_Form_Membership();
219 $rc = $obj->formRule($params, $files, $obj);
220 $this->assertType('array', $rc);
221 $this->assertTrue(array_key_exists('end_date', $rc));
222 }
223
224 /**
225 * Test CRM_Member_Form_Membership::formRule() with end date but no start date and a rolling membership type.
226 */
227 public function testFormRuleRollingEndNoStart() {
228 $unixNow = time();
229 $ymdNow = date('m/d/Y', $unixNow);
230 $unixYearFromNow = $unixNow + (365 * 24 * 60 * 60);
231 $ymdYearFromNow = date('m/d/Y', $unixYearFromNow);
232 $params = array(
233 'join_date' => $ymdNow,
234 'start_date' => '',
235 'end_date' => $ymdYearFromNow,
236 'membership_type_id' => array('23', '15'),
237 );
238 $files = array();
239 $obj = new CRM_Member_Form_Membership();
240 $rc = $obj->formRule($params, $files, $obj);
241 $this->assertType('array', $rc);
242 $this->assertTrue(array_key_exists('start_date', $rc));
243 }
244
245 /**
246 * Test CRM_Member_Form_Membership::formRule() with a parameter
247 * that has an end date and a lifetime membership type
248 */
249 public function testFormRuleRollingLifetimeEnd() {
250 $unixNow = time();
251 $unixYearFromNow = $unixNow + (365 * 24 * 60 * 60);
252 $params = array(
253 'join_date' => date('m/d/Y', $unixNow),
254 'start_date' => date('m/d/Y', $unixNow),
255 'end_date' => date('m/d/Y',
256 $unixYearFromNow
257 ),
258 'membership_type_id' => array('23', '25'),
259 );
260 $files = array();
261 $obj = new CRM_Member_Form_Membership();
262 $rc = $obj->formRule($params, $files, $obj);
263 $this->assertType('array', $rc);
264 $this->assertTrue(array_key_exists('status_id', $rc));
265 }
266
267 /**
268 * Test CRM_Member_Form_Membership::formRule() with a parameter
269 * that has an override and no status
270 */
271 public function testFormRuleOverrideNoStatus() {
272 $unixNow = time();
273 $params = array(
274 'join_date' => date('m/d/Y', $unixNow),
275 'membership_type_id' => array('23', '25'),
276 'is_override' => TRUE,
277 );
278 $files = array();
279 $obj = new CRM_Member_Form_Membership();
280 $rc = $obj->formRule($params, $files, $obj);
281 $this->assertType('array', $rc);
282 $this->assertTrue(array_key_exists('status_id', $rc));
283 }
284
285 /**
286 * Test CRM_Member_Form_Membership::formRule() with a join date
287 * of one month from now and a rolling membership type
288 */
289 public function testFormRuleRollingJoin1MonthFromNow() {
290 $unixNow = time();
291 $unix1MFmNow = $unixNow + (31 * 24 * 60 * 60);
292 $params = array(
293 'join_date' => date('m/d/Y', $unix1MFmNow),
294 'start_date' => '',
295 'end_date' => '',
296 'membership_type_id' => array('23', '15'),
297 );
298 $files = array();
299 $obj = new CRM_Member_Form_Membership();
300 $rc = $obj->formRule($params, $files, $obj);
301
302 // Should have found no valid membership status.
303 $this->assertType('array', $rc);
304 $this->assertTrue(array_key_exists('_qf_default', $rc));
305 }
306
307 /**
308 * Test CRM_Member_Form_Membership::formRule() with a join date of today and a rolling membership type.
309 */
310 public function testFormRuleRollingJoinToday() {
311 $unixNow = time();
312 $params = array(
313 'join_date' => date('m/d/Y', $unixNow),
314 'start_date' => '',
315 'end_date' => '',
316 'membership_type_id' => array('23', '15'),
317 );
318 $files = array();
319 $obj = new CRM_Member_Form_Membership();
320 $rc = $obj->formRule($params, $files, $obj);
321
322 // Should have found New membership status
323 $this->assertTrue($rc);
324 }
325
326 /**
327 * Test CRM_Member_Form_Membership::formRule() with a join date
328 * of one month ago and a rolling membership type
329 */
330 public function testFormRuleRollingJoin1MonthAgo() {
331 $unixNow = time();
332 $unix1MAgo = $unixNow - (31 * 24 * 60 * 60);
333 $params = array(
334 'join_date' => date('m/d/Y', $unix1MAgo),
335 'start_date' => '',
336 'end_date' => '',
337 'membership_type_id' => array('23', '15'),
338 );
339 $files = array();
340 $obj = new CRM_Member_Form_Membership();
341 $rc = $obj->formRule($params, $files, $obj);
342
343 // Should have found New membership status.
344 $this->assertTrue($rc);
345 }
346
347 /**
348 * Test CRM_Member_Form_Membership::formRule() with a join date of six months ago and a rolling membership type.
349 */
350 public function testFormRuleRollingJoin6MonthsAgo() {
351 $unixNow = time();
352 $unix6MAgo = $unixNow - (180 * 24 * 60 * 60);
353 $params = array(
354 'join_date' => date('m/d/Y', $unix6MAgo),
355 'start_date' => '',
356 'end_date' => '',
357 'membership_type_id' => array('23', '15'),
358 );
359 $files = array();
360 $obj = new CRM_Member_Form_Membership();
361 $rc = $obj->formRule($params, $files, $obj);
362
363 // Should have found Current membership status.
364 $this->assertTrue($rc);
365 }
366
367 /**
368 * Test CRM_Member_Form_Membership::formRule() with a join date
369 * of one year+ ago and a rolling membership type
370 */
371 public function testFormRuleRollingJoin1YearAgo() {
372 $unixNow = time();
373 $unix1YAgo = $unixNow - (370 * 24 * 60 * 60);
374 $params = array(
375 'join_date' => date('m/d/Y', $unix1YAgo),
376 'start_date' => '',
377 'end_date' => '',
378 'membership_type_id' => array('23', '15'),
379 );
380 $files = array();
381 $obj = new CRM_Member_Form_Membership();
382 $rc = $obj->formRule($params, $files, $obj);
383
384 // Should have found Grace membership status
385 $this->assertTrue($rc);
386 }
387
388 /**
389 * Test CRM_Member_Form_Membership::formRule() with a join date
390 * of two years ago and a rolling membership type
391 */
392 public function testFormRuleRollingJoin2YearsAgo() {
393 $unixNow = time();
394 $unix2YAgo = $unixNow - (2 * 365 * 24 * 60 * 60);
395 $params = array(
396 'join_date' => date('m/d/Y', $unix2YAgo),
397 'start_date' => '',
398 'end_date' => '',
399 'membership_type_id' => array('23', '15'),
400 );
401 $files = array();
402 $obj = new CRM_Member_Form_Membership();
403 $rc = $obj->formRule($params, $files, $obj);
404
405 // Should have found Expired membership status
406 $this->assertTrue($rc);
407 }
408
409 /**
410 * Test CRM_Member_Form_Membership::formRule() with a join date
411 * of six months ago and a fixed membership type
412 */
413 public function testFormRuleFixedJoin6MonthsAgo() {
414 $unixNow = time();
415 $unix6MAgo = $unixNow - (180 * 24 * 60 * 60);
416 $params = array(
417 'join_date' => date('m/d/Y', $unix6MAgo),
418 'start_date' => '',
419 'end_date' => '',
420 'membership_type_id' => array('23', '7'),
421 );
422 $files = array();
423 $obj = new CRM_Member_Form_Membership();
424 $rc = $obj->formRule($params, $files, $obj);
425
426 // Should have found Current membership status
427 $this->assertTrue($rc);
428 }
429
430 /**
431 * Test the submit function of the membership form.
432 */
433 public function testSubmit() {
434 $form = $this->getForm();
435 $form->_mode = 'test';
436 $this->createLoggedInUser();
437 $params = array(
438 'cid' => $this->_individualId,
439 'join_date' => date('m/d/Y', time()),
440 'start_date' => '',
441 'end_date' => '',
442 // This format reflects the 23 being the organisation & the 25 being the type.
443 'membership_type_id' => array(23, $this->membershipTypeAnnualFixedID),
444 'auto_renew' => '0',
445 'max_related' => '',
446 'num_terms' => '1',
447 'source' => '',
448 'total_amount' => '50.00',
449 'financial_type_id' => '2', //Member dues, see data.xml
450 'soft_credit_type_id' => '',
451 'soft_credit_contact_id' => '',
452 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
453 'receipt_text_signup' => 'Thank you text',
454 'payment_processor_id' => $this->_paymentProcessorID,
455 'credit_card_number' => '4111111111111111',
456 'cvv2' => '123',
457 'credit_card_exp_date' => array(
458 'M' => '9',
459 'Y' => '2024', // TODO: Future proof
460 ),
461 'credit_card_type' => 'Visa',
462 'billing_first_name' => 'Test',
463 'billing_middlename' => 'Last',
464 'billing_street_address-5' => '10 Test St',
465 'billing_city-5' => 'Test',
466 'billing_state_province_id-5' => '1003',
467 'billing_postal_code-5' => '90210',
468 'billing_country_id-5' => '1228',
469 );
470 $form->_contactID = $this->_individualId;
471 $form->testSubmit($params);
472 $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId));
473 $this->callAPISuccessGetCount('ContributionRecur', array('contact_id' => $this->_individualId), 0);
474 $contribution = $this->callAPISuccess('Contribution', 'get', array(
475 'contact_id' => $this->_individualId,
476 'is_test' => TRUE,
477 ));
478
479 $this->callAPISuccessGetCount('LineItem', array(
480 'entity_id' => $membership['id'],
481 'entity_table' => 'civicrm_membership',
482 'contribution_id' => $contribution['id'],
483 ), 1);
484 }
485
486 /**
487 * Test the submit function of the membership form.
488 */
489 public function testSubmitRecur() {
490 $form = $this->getForm();
491
492 $this->callAPISuccess('MembershipType', 'create', array(
493 'id' => $this->membershipTypeAnnualFixedID,
494 'duration_unit' => 'month',
495 'duration_interval' => 1,
496 'auto_renew' => TRUE,
497 ));
498 $form->preProcess();
499 $this->createLoggedInUser();
500 $params = $this->getBaseSubmitParams();
501 $form->_mode = 'test';
502 $form->_contactID = $this->_individualId;
503 $form->testSubmit($params);
504 $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId));
505 $this->callAPISuccessGetCount('ContributionRecur', array('contact_id' => $this->_individualId), 1);
506
507 $contribution = $this->callAPISuccess('Contribution', 'get', array(
508 'contact_id' => $this->_individualId,
509 'is_test' => TRUE,
510 ));
511
512 // CRM-16992.
513 $this->callAPISuccessGetCount('LineItem', array(
514 'entity_id' => $membership['id'],
515 'entity_table' => 'civicrm_membership',
516 'contribution_id' => $contribution['id'],
517 ), 1);
518 }
519
520 /**
521 * Test the submit function of the membership form.
522 */
523 public function testSubmitPayLaterWithBilling() {
524 $form = $this->getForm(NULL);
525 $this->createLoggedInUser();
526 $params = array(
527 'cid' => $this->_individualId,
528 'join_date' => date('m/d/Y', time()),
529 'start_date' => '',
530 'end_date' => '',
531 // This format reflects the 23 being the organisation & the 25 being the type.
532 'membership_type_id' => array(23, $this->membershipTypeAnnualFixedID),
533 'auto_renew' => '0',
534 'max_related' => '',
535 'num_terms' => '2',
536 'source' => '',
537 'total_amount' => '50.00',
538 //Member dues, see data.xml
539 'financial_type_id' => '2',
540 'soft_credit_type_id' => '',
541 'soft_credit_contact_id' => '',
542 'payment_instrument_id' => 4,
543 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
544 'receipt_text_signup' => 'Thank you text',
545 'payment_processor_id' => $this->_paymentProcessorID,
546 'record_contribution' => TRUE,
547 'trxn_id' => 777,
548 'contribution_status_id' => 2,
549 'billing_first_name' => 'Test',
550 'billing_middlename' => 'Last',
551 'billing_street_address-5' => '10 Test St',
552 'billing_city-5' => 'Test',
553 'billing_state_province_id-5' => '1003',
554 'billing_postal_code-5' => '90210',
555 'billing_country_id-5' => '1228',
556 );
557 $form->_contactID = $this->_individualId;
558
559 $form->testSubmit($params);
560 $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId));
561 $contribution = $this->callAPISuccessGetSingle('Contribution', array(
562 'contact_id' => $this->_individualId,
563 'contribution_status_id' => 2,
564 ));
565 $this->assertEquals($contribution['trxn_id'], 777);
566
567 $this->callAPISuccessGetCount('LineItem', array(
568 'entity_id' => $membership['id'],
569 'entity_table' => 'civicrm_membership',
570 'contribution_id' => $contribution['id'],
571 ), 1);
572 $this->callAPISuccessGetSingle('address', array(
573 'contact_id' => $this->_individualId,
574 'street_address' => '10 Test St',
575 'postal_code' => 90210,
576 ));
577 }
578
579 /**
580 * Test the submit function of the membership form.
581 */
582 public function testSubmitRecurCompleteInstant() {
583 $form = $this->getForm();
584
585 $processor = Civi\Payment\System::singleton()->getById($this->_paymentProcessorID);
586 $processor->setDoDirectPaymentResult(array(
587 'payment_status_id' => 1,
588 'trxn_id' => 'kettles boil water',
589 'fee_amount' => .14,
590 ));
591 $this->callAPISuccess('MembershipType', 'create', array(
592 'id' => $this->membershipTypeAnnualFixedID,
593 'duration_unit' => 'month',
594 'duration_interval' => 1,
595 'auto_renew' => TRUE,
596 ));
597 $form->preProcess();
598 $this->createLoggedInUser();
599 $params = $this->getBaseSubmitParams();
600 $form->_mode = 'test';
601 $form->_contactID = $this->_individualId;
602 $form->testSubmit($params);
603 $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId));
604 $this->callAPISuccessGetCount('ContributionRecur', array('contact_id' => $this->_individualId), 1);
605
606 $contribution = $this->callAPISuccess('Contribution', 'getsingle', array(
607 'contact_id' => $this->_individualId,
608 'is_test' => TRUE,
609 ));
610
611 $this->assertEquals(.14, $contribution['fee_amount']);
612 $this->assertEquals('kettles boil water', $contribution['trxn_id']);
613
614 $this->callAPISuccessGetCount('LineItem', array(
615 'entity_id' => $membership['id'],
616 'entity_table' => 'civicrm_membership',
617 'contribution_id' => $contribution['id'],
618 ), 1);
619
620 }
621
622 /**
623 * Get a membership form object.
624 *
625 * We need to instantiate the form to run preprocess, which means we have to trick it about the request method.
626 *
627 * @return \CRM_Member_Form_Membership
628 */
629 protected function getForm() {
630 $form = new CRM_Member_Form_Membership();
631 $_SERVER['REQUEST_METHOD'] = 'GET';
632 $form->controller = new CRM_Core_Controller();
633 $form->_bltID = 5;
634 return $form;
635 }
636
637 /**
638 * @return array
639 */
640 protected function getBaseSubmitParams() {
641 $params = array(
642 'cid' => $this->_individualId,
643 'price_set_id' => 0,
644 'join_date' => date('m/d/Y', time()),
645 'start_date' => '',
646 'end_date' => '',
647 'campaign_id' => '',
648 // This format reflects the 23 being the organisation & the 25 being the type.
649 'membership_type_id' => array(23, $this->membershipTypeAnnualFixedID),
650 'auto_renew' => '1',
651 'is_recur' => 1,
652 'max_related' => 0,
653 'num_terms' => '1',
654 'source' => '',
655 'total_amount' => '77.00',
656 'financial_type_id' => '2', //Member dues, see data.xml
657 'soft_credit_type_id' => 11,
658 'soft_credit_contact_id' => '',
659 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
660 'receipt_text' => 'Thank you text',
661 'payment_processor_id' => $this->_paymentProcessorID,
662 'credit_card_number' => '4111111111111111',
663 'cvv2' => '123',
664 'credit_card_exp_date' => array(
665 'M' => '9',
666 'Y' => '2019', // TODO: Future proof
667 ),
668 'credit_card_type' => 'Visa',
669 'billing_first_name' => 'Test',
670 'billing_middlename' => 'Last',
671 'billing_street_address-5' => '10 Test St',
672 'billing_city-5' => 'Test',
673 'billing_state_province_id-5' => '1003',
674 'billing_postal_code-5' => '90210',
675 'billing_country_id-5' => '1228',
676 );
677 return $params;
678 }
679
680 }