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