3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2017 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
29 * File for the MembershipTest class
33 * @author Walt Haas <walt@dharmatech.org> (801) 534-1262
37 * Test CRM_Member_Form_Membership functions.
42 class CRM_Member_Form_MembershipTest
extends CiviUnitTestCase
{
45 * Assume empty database with just civicrm_data.
47 protected $_individualId;
48 protected $_contribution;
49 protected $_financialTypeId = 1;
50 protected $_apiversion;
51 protected $_entity = 'Membership';
53 protected $_ids = array();
54 protected $_paymentProcessorID;
57 * Membership type ID for annual fixed membership.
61 protected $membershipTypeAnnualFixedID;
64 * Parameters to create payment processor.
68 protected $_processorParams = array();
71 * ID of created membership.
75 protected $_membershipID;
78 * Payment instrument mapping.
82 protected $paymentInstruments = array();
90 * Test setup for every test.
92 * Connect to the database, truncate the tables that will be used
93 * and redirect stdin to a temporary file.
95 public function setUp() {
96 $this->_apiversion
= 3;
99 $this->_individualId
= $this->individualCreate();
100 $this->_paymentProcessorID
= $this->processorCreate();
102 $op = new PHPUnit_Extensions_Database_Operation_Insert();
103 $op->execute($this->_dbconn
,
104 $this->createFlatXMLDataSet(
105 dirname(__FILE__
) . '/dataset/data.xml'
108 $membershipTypeAnnualFixed = $this->callAPISuccess('membership_type', 'create', array(
110 'name' => "AnnualFixed",
111 'member_of_contact_id' => 23,
112 '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,
121 $this->membershipTypeAnnualFixedID
= $membershipTypeAnnualFixed['id'];
123 $instruments = $this->callAPISuccess('contribution', 'getoptions', array('field' => 'payment_instrument_id'));
124 $this->paymentInstruments
= $instruments['values'];
128 * Clean up after each test.
130 public function tearDown() {
131 $this->quickCleanUpFinancialEntities();
134 'civicrm_relationship',
135 'civicrm_membership_type',
136 'civicrm_membership',
140 foreach (array(17, 18, 23, 32) as $contactID) {
141 $this->callAPISuccess('contact', 'delete', array('id' => $contactID, 'skip_undelete' => TRUE));
143 $this->callAPISuccess('relationship_type', 'delete', array('id' => 20));
147 * Test CRM_Member_Form_Membership::buildQuickForm()
149 //function testCRMMemberFormMembershipBuildQuickForm()
151 // throw new PHPUnit_Framework_IncompleteTestError( "not implemented" );
155 * Test CRM_Member_Form_Membership::formRule() with a parameter
156 * that has an empty contact_select_id value
158 public function testFormRuleEmptyContact() {
160 'contact_select_id' => 0,
161 'membership_type_id' => array(1 => NULL),
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));
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));
176 * Test that form rule fails if start date is before join date.
178 * Test CRM_Member_Form_Membership::formRule() with a parameter
179 * that has an start date before the join date and a rolling
182 public function testFormRuleRollingEarlyStart() {
184 $ymdNow = date('m/d/Y', $unixNow);
185 $unixYesterday = $unixNow - (24 * 60 * 60);
186 $ymdYesterday = date('m/d/Y', $unixYesterday);
188 'join_date' => $ymdNow,
189 'start_date' => $ymdYesterday,
191 'membership_type_id' => array('23', '15'),
194 $obj = new CRM_Member_Form_Membership();
195 $rc = call_user_func(array('CRM_Member_Form_Membership', 'formRule'),
196 $params, $files, $obj
198 $this->assertType('array', $rc);
199 $this->assertTrue(array_key_exists('start_date', $rc));
203 * Test CRM_Member_Form_Membership::formRule() with a parameter
204 * that has an end date before the start date and a rolling
207 public function testFormRuleRollingEarlyEnd() {
209 $ymdNow = date('m/d/Y', $unixNow);
210 $unixYesterday = $unixNow - (24 * 60 * 60);
211 $ymdYesterday = date('m/d/Y', $unixYesterday);
213 'join_date' => $ymdNow,
214 'start_date' => $ymdNow,
215 'end_date' => $ymdYesterday,
216 'membership_type_id' => array('23', '15'),
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));
226 * Test CRM_Member_Form_Membership::formRule() with end date but no start date and a rolling membership type.
228 public function testFormRuleRollingEndNoStart() {
230 $ymdNow = date('m/d/Y', $unixNow);
231 $unixYearFromNow = $unixNow +
(365 * 24 * 60 * 60);
232 $ymdYearFromNow = date('m/d/Y', $unixYearFromNow);
234 'join_date' => $ymdNow,
236 'end_date' => $ymdYearFromNow,
237 'membership_type_id' => array('23', '15'),
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));
247 * Test CRM_Member_Form_Membership::formRule() with a parameter
248 * that has an end date and a lifetime membership type
250 public function testFormRuleRollingLifetimeEnd() {
252 $unixYearFromNow = $unixNow +
(365 * 24 * 60 * 60);
254 'join_date' => date('m/d/Y', $unixNow),
255 'start_date' => date('m/d/Y', $unixNow),
256 'end_date' => date('m/d/Y',
259 'membership_type_id' => array('23', '25'),
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));
269 * Test CRM_Member_Form_Membership::formRule() with a parameter
270 * that has an override and no status
272 public function testFormRuleOverrideNoStatus() {
275 'join_date' => date('m/d/Y', $unixNow),
276 'membership_type_id' => array('23', '25'),
277 'is_override' => TRUE,
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));
287 * Test CRM_Member_Form_Membership::formRule() with a join date
288 * of one month from now and a rolling membership type
290 public function testFormRuleRollingJoin1MonthFromNow() {
292 $unix1MFmNow = $unixNow +
(31 * 24 * 60 * 60);
294 'join_date' => date('m/d/Y', $unix1MFmNow),
297 'membership_type_id' => array('23', '15'),
300 $obj = new CRM_Member_Form_Membership();
301 $rc = $obj->formRule($params, $files, $obj);
303 // Should have found no valid membership status.
304 $this->assertType('array', $rc);
305 $this->assertTrue(array_key_exists('_qf_default', $rc));
309 * Test CRM_Member_Form_Membership::formRule() with a join date of today and a rolling membership type.
311 public function testFormRuleRollingJoinToday() {
314 'join_date' => date('m/d/Y', $unixNow),
317 'membership_type_id' => array('23', '15'),
320 $obj = new CRM_Member_Form_Membership();
321 $rc = $obj->formRule($params, $files, $obj);
323 // Should have found New membership status
324 $this->assertTrue($rc);
328 * Test CRM_Member_Form_Membership::formRule() with a join date
329 * of one month ago and a rolling membership type
331 public function testFormRuleRollingJoin1MonthAgo() {
333 $unix1MAgo = $unixNow - (31 * 24 * 60 * 60);
335 'join_date' => date('m/d/Y', $unix1MAgo),
338 'membership_type_id' => array('23', '15'),
341 $obj = new CRM_Member_Form_Membership();
342 $rc = $obj->formRule($params, $files, $obj);
344 // Should have found New membership status.
345 $this->assertTrue($rc);
349 * Test CRM_Member_Form_Membership::formRule() with a join date of six months ago and a rolling membership type.
351 public function testFormRuleRollingJoin6MonthsAgo() {
353 $unix6MAgo = $unixNow - (180 * 24 * 60 * 60);
355 'join_date' => date('m/d/Y', $unix6MAgo),
358 'membership_type_id' => array('23', '15'),
361 $obj = new CRM_Member_Form_Membership();
362 $rc = $obj->formRule($params, $files, $obj);
364 // Should have found Current membership status.
365 $this->assertTrue($rc);
369 * Test CRM_Member_Form_Membership::formRule() with a join date
370 * of one year+ ago and a rolling membership type
372 public function testFormRuleRollingJoin1YearAgo() {
374 $unix1YAgo = $unixNow - (370 * 24 * 60 * 60);
376 'join_date' => date('m/d/Y', $unix1YAgo),
379 'membership_type_id' => array('23', '15'),
382 $obj = new CRM_Member_Form_Membership();
383 $rc = $obj->formRule($params, $files, $obj);
385 // Should have found Grace membership status
386 $this->assertTrue($rc);
390 * Test CRM_Member_Form_Membership::formRule() with a join date
391 * of two years ago and a rolling membership type
393 public function testFormRuleRollingJoin2YearsAgo() {
395 $unix2YAgo = $unixNow - (2 * 365 * 24 * 60 * 60);
397 'join_date' => date('m/d/Y', $unix2YAgo),
400 'membership_type_id' => array('23', '15'),
403 $obj = new CRM_Member_Form_Membership();
404 $rc = $obj->formRule($params, $files, $obj);
406 // Should have found Expired membership status
407 $this->assertTrue($rc);
411 * Test CRM_Member_Form_Membership::formRule() with a join date
412 * of six months ago and a fixed membership type
414 public function testFormRuleFixedJoin6MonthsAgo() {
416 $unix6MAgo = $unixNow - (180 * 24 * 60 * 60);
418 'join_date' => date('m/d/Y', $unix6MAgo),
421 'membership_type_id' => array('23', '7'),
424 $obj = new CRM_Member_Form_Membership();
425 $rc = $obj->formRule($params, $files, $obj);
427 // Should have found Current membership status
428 $this->assertTrue($rc);
432 * Test the submit function of the membership form.
434 public function testSubmit() {
435 $form = $this->getForm();
437 $this->mut
= new CiviMailUtils($this, TRUE);
438 $form->_mode
= 'test';
439 $this->createLoggedInUser();
441 'cid' => $this->_individualId
,
442 'join_date' => date('m/d/Y', time()),
445 // This format reflects the 23 being the organisation & the 25 being the type.
446 'membership_type_id' => array(23, $this->membershipTypeAnnualFixedID
),
451 'total_amount' => '50.00',
452 'financial_type_id' => '2', //Member dues, see data.xml
453 'soft_credit_type_id' => '',
454 'soft_credit_contact_id' => '',
455 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
456 'payment_processor_id' => $this->_paymentProcessorID
,
457 'credit_card_number' => '4111111111111111',
459 'credit_card_exp_date' => array(
461 'Y' => '2024', // TODO: Future proof
463 'credit_card_type' => 'Visa',
464 'billing_first_name' => 'Test',
465 'billing_middlename' => 'Last',
466 'billing_street_address-5' => '10 Test St',
467 'billing_city-5' => 'Test',
468 'billing_state_province_id-5' => '1003',
469 'billing_postal_code-5' => '90210',
470 'billing_country_id-5' => '1228',
471 'send_receipt' => TRUE,
472 'receipt_text' => 'Receipt text',
474 $form->_contactID
= $this->_individualId
;
475 $form->testSubmit($params);
476 $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId
));
477 $this->callAPISuccessGetCount('ContributionRecur', array('contact_id' => $this->_individualId
), 0);
478 $contribution = $this->callAPISuccess('Contribution', 'get', array(
479 'contact_id' => $this->_individualId
,
483 //CRM-20264 : Check that CC type and number (last 4 digit) is stored during backoffice membership payment
484 $lastFinancialTrxnId = CRM_Core_BAO_FinancialTrxn
::getFinancialTrxnId($contribution['id'], 'DESC');
485 $financialTrxn = $this->callAPISuccessGetSingle(
488 'id' => $lastFinancialTrxnId['financialTrxnId'],
489 'return' => array('card_type_id', 'pan_truncation'),
492 $this->assertEquals(1, $financialTrxn['card_type_id']);
493 $this->assertEquals(1111, $financialTrxn['pan_truncation']);
495 $this->callAPISuccessGetCount('LineItem', array(
496 'entity_id' => $membership['id'],
497 'entity_table' => 'civicrm_membership',
498 'contribution_id' => $contribution['id'],
501 $this->_checkFinancialRecords(array(
502 'id' => $contribution['id'],
503 'total_amount' => 50,
504 'financial_account_id' => 2,
505 'payment_instrument_id' => $this->callAPISuccessGetValue('PaymentProcessor', array(
506 'id' => $this->_paymentProcessorID
,
507 'return' => 'payment_instrument_id',
510 $this->mut
->checkMailLog(array(
518 * Test the submit function of the membership form on membership type change.
519 * Check if the related contribuion is also updated if the minimum_fee didn't match
521 public function testContributionUpdateOnMembershipTypeChange() {
522 // Step 1: Create a Membership via backoffice whose with 50.00 payment
523 $form = $this->getForm();
525 $this->mut
= new CiviMailUtils($this, TRUE);
526 $this->createLoggedInUser();
527 $priceSet = $this->callAPISuccess('PriceSet', 'Get', array("extends" => "CiviMember"));
528 $form->set('priceSetId', $priceSet['id']);
529 CRM_Price_BAO_PriceSet
::buildPriceSet($form);
531 'cid' => $this->_individualId
,
532 'join_date' => date('m/d/Y', time()),
535 // This format reflects the 23 being the organisation & the 25 being the type.
536 'membership_type_id' => array(23, $this->membershipTypeAnnualFixedID
),
537 'record_contribution' => 1,
538 'total_amount' => 50,
539 'receive_date' => date('m/d/Y', time()),
540 'receive_date_time' => '08:36PM',
541 'payment_instrument_id' => array_search('Check', $this->paymentInstruments
),
542 'contribution_status_id' => CRM_Core_PseudoConstant
::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'),
543 'financial_type_id' => '2', //Member dues, see data.xml
544 'payment_processor_id' => $this->_paymentProcessorID
,
546 $form->_contactID
= $this->_individualId
;
547 $form->testSubmit($params);
548 $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId
));
549 // check the membership status after partial payment, if its Pending
550 $this->assertEquals(array_search('New', CRM_Member_PseudoConstant
::membershipStatus()), $membership['status_id']);
551 $contribution = $this->callAPISuccessGetSingle('Contribution', array(
552 'contact_id' => $this->_individualId
,
554 $this->assertEquals('Completed', $contribution['contribution_status']);
555 $this->assertEquals(50.00, $contribution['total_amount']);
556 $this->assertEquals(50.00, $contribution['net_amount']);
558 // Step 2: Change the membership type whose minimum free is less than earlier membership
559 $secondMembershipType = $this->callAPISuccess('membership_type', 'create', array(
561 'name' => "Second Test Membership",
562 'member_of_contact_id' => 23,
563 'duration_unit' => "month",
565 'duration_interval' => 1,
566 'period_type' => "fixed",
567 'fixed_period_start_day' => "101",
568 'fixed_period_rollover_day' => "1231",
569 'relationship_type_id' => 20,
570 'financial_type_id' => 2,
572 Civi
::settings()->set('update_contribution_on_membership_type_change', TRUE);
573 $form = $this->getForm();
575 $form->_id
= $membership['id'];
576 $form->set('priceSetId', $priceSet['id']);
577 CRM_Price_BAO_PriceSet
::buildPriceSet($form);
578 $form->_action
= CRM_Core_Action
::UPDATE
;
580 'cid' => $this->_individualId
,
581 'join_date' => date('m/d/Y', time()),
584 // This format reflects the 23 being the organisation & the 25 being the type.
585 'membership_type_id' => array(23, $secondMembershipType['id']),
586 'record_contribution' => 1,
588 'total_amount' => 25,
589 'receive_date' => date('m/d/Y', time()),
590 'receive_date_time' => '08:36PM',
591 'payment_instrument_id' => array_search('Check', $this->paymentInstruments
),
592 'financial_type_id' => '2', //Member dues, see data.xml
593 'payment_processor_id' => $this->_paymentProcessorID
,
595 $form->_contactID
= $this->_individualId
;
596 $form->testSubmit($params);
597 $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId
));
598 // check the membership status after partial payment, if its Pending
599 $contribution = $this->callAPISuccessGetSingle('Contribution', array(
600 'contact_id' => $this->_individualId
,
602 $payment = CRM_Contribute_BAO_Contribution
::getPaymentInfo($membership['id'], 'membership', FALSE, TRUE);
603 // Check the contribution status on membership type change whose minimum fee was less than earlier memebership
604 $this->assertEquals('Pending refund', $contribution['contribution_status']);
605 // Earlier paid amount
606 $this->assertEquals(50, $payment['paid']);
608 $this->assertEquals(-25, $payment['balance']);
612 * Test the submit function of the membership form.
614 public function testSubmitRecur() {
615 $form = $this->getForm();
617 $this->callAPISuccess('MembershipType', 'create', array(
618 'id' => $this->membershipTypeAnnualFixedID
,
619 'duration_unit' => 'month',
620 'duration_interval' => 1,
621 'auto_renew' => TRUE,
624 $this->createLoggedInUser();
625 $params = $this->getBaseSubmitParams();
626 $form->_mode
= 'test';
627 $form->_contactID
= $this->_individualId
;
628 $form->testSubmit($params);
629 $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId
));
630 $this->callAPISuccessGetCount('ContributionRecur', array('contact_id' => $this->_individualId
), 1);
632 $contribution = $this->callAPISuccess('Contribution', 'get', array(
633 'contact_id' => $this->_individualId
,
638 $this->callAPISuccessGetCount('LineItem', array(
639 'entity_id' => $membership['id'],
640 'entity_table' => 'civicrm_membership',
641 'contribution_id' => $contribution['id'],
646 * Test membership form with Failed Contribution.
648 public function testFormStatusUpdate() {
649 $form = $this->getForm();
651 $this->_individualId
= $this->createLoggedInUser();
653 'contact_id' => $this->_individualId
,
654 'membership_type_id' => $this->membershipTypeAnnualFixedID
,
655 'is_override' => TRUE,
656 'status_id' => array_search('Cancelled', CRM_Member_PseudoConstant
::membershipStatus()),
658 $params = $this->getBaseSubmitParams();
659 $params['id'] = $this->contactMembershipCreate($memParams);
660 unset($params['price_set_id']);
661 unset($params['credit_card_number']);
662 unset($params['cvv2']);
663 unset($params['credit_card_exp_date']);
664 unset($params['credit_card_type']);
665 unset($params['send_receipt']);
666 unset($params['is_recur']);
668 // process date params to mysql date format.
670 'join_date' => 'joinDate',
671 'start_date' => 'startDate',
672 'end_date' => 'endDate',
674 $previousStatus = CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_Membership', $params['id'], 'status_id');
675 foreach ($dateTypes as $dateField => $dateVariable) {
676 $params[$dateField] = CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_Membership', $params['id'], $dateField);
678 $form->_id
= $params['id'];
680 $form->_contactID
= $this->_individualId
;
682 $form->testSubmit($params);
683 $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId
));
684 //Assert the status remains when the form dates are not modified.
685 $this->assertEquals($membership['status_id'], $previousStatus);
689 * CRM-20946: Test the financial entires especially the reversed amount,
690 * after related Contribution is cancelled
692 public function testFinancialEntiriesOnCancelledContribution() {
693 $form = $this->getForm(NULL);
695 $this->createLoggedInUser();
697 // create a price-set of price-field of type checkbox and each price-option corrosponds to a membership type
698 $priceSet = $this->callAPISuccess('price_set', 'create', array(
699 'is_quick_config' => 0,
700 'extends' => 'CiviMember',
701 'financial_type_id' => 1,
702 'title' => 'my Page',
704 $priceSetID = $priceSet['id'];
705 // create respective checkbox price-field
706 $priceField = $this->callAPISuccess('price_field', 'create', array(
707 'price_set_id' => $priceSetID,
708 'label' => 'Memberships',
709 'html_type' => 'Checkbox',
711 $priceFieldID = $priceField['id'];
712 // create two price options, each represent a membership type of amount 20 and 10 respectively
713 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
714 'price_set_id' => $priceSetID,
715 'price_field_id' => $priceField['id'],
716 'label' => 'Long Haired Goat',
718 'financial_type_id' => 'Donation',
719 'membership_type_id' => 15,
720 'membership_num_terms' => 1,
723 $pfvIDs = array($priceFieldValue['id'] => 1);
724 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
725 'price_set_id' => $priceSetID,
726 'price_field_id' => $priceField['id'],
727 'label' => 'Shoe-eating Goat',
729 'financial_type_id' => 'Donation',
730 'membership_type_id' => 35,
731 'membership_num_terms' => 2,
734 $pfvIDs[$priceFieldValue['id']] = 1;
736 // register for both of this memberships via backoffice membership form submission
738 'cid' => $this->_individualId
,
739 'join_date' => date('m/d/Y', time()),
742 // This format reflects the 23 being the organisation & the 25 being the type.
743 "price_$priceFieldID" => $pfvIDs,
744 "price_set_id" => $priceSetID,
745 'membership_type_id' => array(1 => 0),
750 'total_amount' => '30.00',
751 //Member dues, see data.xml
752 'financial_type_id' => '2',
753 'soft_credit_type_id' => '',
754 'soft_credit_contact_id' => '',
755 'payment_instrument_id' => 4,
756 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
757 'receipt_text_signup' => 'Thank you text',
758 'payment_processor_id' => $this->_paymentProcessorID
,
759 'record_contribution' => TRUE,
761 'contribution_status_id' => CRM_Core_PseudoConstant
::getKey('CRM_Contribute_DAO_Contribution', 'contribution_status_id', 'Pending'),
762 'billing_first_name' => 'Test',
763 'billing_middlename' => 'Last',
764 'billing_street_address-5' => '10 Test St',
765 'billing_city-5' => 'Test',
766 'billing_state_province_id-5' => '1003',
767 'billing_postal_code-5' => '90210',
768 'billing_country_id-5' => '1228',
770 $form->testSubmit($params);
772 // cancel the related contribution via API
773 $contribution = $this->callAPISuccessGetSingle('Contribution', array(
774 'contact_id' => $this->_individualId
,
775 'contribution_status_id' => 2,
777 $this->callAPISuccess('Contribution', 'create', array(
778 'id' => $contribution['id'],
779 'contribution_status_id' => CRM_Core_PseudoConstant
::getKey('CRM_Contribute_DAO_Contribution', 'contribution_status_id', 'Cancelled'),
782 // fetch financial_trxn ID of the related contribution
783 $sql = "SELECT financial_trxn_id
784 FROM civicrm_entity_financial_trxn
785 WHERE entity_id = %1 AND entity_table = 'civicrm_contribution'
789 $financialTrxnID = CRM_Core_DAO
::singleValueQuery($sql, array(1 => array($contribution['id'], 'Int')));
791 // fetch entity_financial_trxn records and compare their cancelled records
792 $result = $this->callAPISuccess('EntityFinancialTrxn', 'Get', array(
793 'financial_trxn_id' => $financialTrxnID,
794 'entity_table' => 'civicrm_financial_item',
796 // compare the reversed amounts of respective memberships after cancelling contribution
797 $cancelledMembershipAmounts = array(
802 foreach ($result['values'] as $record) {
803 $this->assertEquals($cancelledMembershipAmounts[$count], $record['amount']);
809 * Test the submit function of the membership form.
811 public function testSubmitPayLaterWithBilling() {
812 $form = $this->getForm(NULL);
814 $this->createLoggedInUser();
816 'cid' => $this->_individualId
,
817 'join_date' => date('m/d/Y', time()),
820 // This format reflects the 23 being the organisation & the 25 being the type.
821 'membership_type_id' => array(23, $this->membershipTypeAnnualFixedID
),
826 'total_amount' => '50.00',
827 //Member dues, see data.xml
828 'financial_type_id' => '2',
829 'soft_credit_type_id' => '',
830 'soft_credit_contact_id' => '',
831 'payment_instrument_id' => 4,
832 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
833 'receipt_text_signup' => 'Thank you text',
834 'payment_processor_id' => $this->_paymentProcessorID
,
835 'record_contribution' => TRUE,
837 'contribution_status_id' => 2,
838 'billing_first_name' => 'Test',
839 'billing_middlename' => 'Last',
840 'billing_street_address-5' => '10 Test St',
841 'billing_city-5' => 'Test',
842 'billing_state_province_id-5' => '1003',
843 'billing_postal_code-5' => '90210',
844 'billing_country_id-5' => '1228',
846 $form->_contactID
= $this->_individualId
;
848 $form->testSubmit($params);
849 $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId
));
850 $contribution = $this->callAPISuccessGetSingle('Contribution', array(
851 'contact_id' => $this->_individualId
,
852 'contribution_status_id' => 2,
854 $this->assertEquals($contribution['trxn_id'], 777);
856 $this->callAPISuccessGetCount('LineItem', array(
857 'entity_id' => $membership['id'],
858 'entity_table' => 'civicrm_membership',
859 'contribution_id' => $contribution['id'],
861 $this->callAPISuccessGetSingle('address', array(
862 'contact_id' => $this->_individualId
,
863 'street_address' => '10 Test St',
864 'postal_code' => 90210,
869 * Test if membership is updated to New after contribution
870 * is updated from Partially paid to Completed.
872 public function testSubmitUpdateMembershipFromPartiallyPaid() {
873 $memStatus = CRM_Member_BAO_Membership
::buildOptions('status_id', 'validate');
875 //Perform a pay later membership contribution.
876 $this->testSubmitPayLaterWithBilling();
877 $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId
));
878 $this->assertEquals($membership['status_id'], array_search('Pending', $memStatus));
879 $contribution = $this->callAPISuccessGetSingle('MembershipPayment', array(
880 'membership_id' => $membership['id'],
883 //Update contribution to Partially paid.
884 $prevContribution = $this->callAPISuccess('Contribution', 'create', array(
885 'id' => $contribution['contribution_id'],
886 'contribution_status_id' => 'Partially paid',
888 $prevContribution = $prevContribution['values'][1];
890 //Complete the contribution from offline form.
891 $form = new CRM_Contribute_Form_Contribution();
892 $submitParams = array(
893 'id' => $contribution['contribution_id'],
894 'contribution_status_id' => CRM_Core_PseudoConstant
::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'),
897 $fields = array('total_amount', 'net_amount', 'financial_type_id', 'receive_date', 'contact_id', 'payment_instrument_id');
898 foreach ($fields as $val) {
899 $submitParams[$val] = $prevContribution[$val];
901 $form->testSubmit($submitParams, CRM_Core_Action
::UPDATE
);
903 //Check if Membership is updated to New.
904 $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId
));
905 $this->assertEquals($membership['status_id'], array_search('New', $memStatus));
909 * Test the submit function of the membership form.
911 public function testSubmitRecurCompleteInstant() {
912 $form = $this->getForm();
913 $mut = new CiviMailUtils($this, TRUE);
914 $processor = Civi\Payment\System
::singleton()->getById($this->_paymentProcessorID
);
915 $processor->setDoDirectPaymentResult(array(
916 'payment_status_id' => 1,
917 'trxn_id' => 'kettles boil water',
920 $processorDetail = $processor->getPaymentProcessor();
921 $this->callAPISuccess('MembershipType', 'create', array(
922 'id' => $this->membershipTypeAnnualFixedID
,
923 'duration_unit' => 'month',
924 'duration_interval' => 1,
925 'auto_renew' => TRUE,
928 $this->createLoggedInUser();
929 $params = $this->getBaseSubmitParams();
930 $form->_mode
= 'test';
931 $form->_contactID
= $this->_individualId
;
932 $form->testSubmit($params);
933 $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId
));
934 $this->callAPISuccessGetCount('ContributionRecur', array('contact_id' => $this->_individualId
), 1);
936 $contribution = $this->callAPISuccess('Contribution', 'getsingle', array(
937 'contact_id' => $this->_individualId
,
941 $this->assertEquals(.14, $contribution['fee_amount']);
942 $this->assertEquals('kettles boil water', $contribution['trxn_id']);
943 $this->assertEquals($processorDetail['payment_instrument_id'], $contribution['payment_instrument_id']);
945 $this->callAPISuccessGetCount('LineItem', array(
946 'entity_id' => $membership['id'],
947 'entity_table' => 'civicrm_membership',
948 'contribution_id' => $contribution['id'],
950 $mut->checkMailLog(array(
951 '===========================================================
952 Billing Name and Address
953 ===========================================================
958 '===========================================================
959 Membership Information
960 ===========================================================
961 Membership Type: AnnualFixed
962 Membership Start Date: ',
963 '===========================================================
964 Credit Card Information
965 ===========================================================
976 * Test membership form with Failed Contribution.
978 public function testFormWithFailedContribution() {
979 $form = $this->getForm();
981 $this->createLoggedInUser();
982 $params = $this->getBaseSubmitParams();
983 unset($params['price_set_id']);
984 unset($params['credit_card_number']);
985 unset($params['cvv2']);
986 unset($params['credit_card_exp_date']);
987 unset($params['credit_card_type']);
988 unset($params['send_receipt']);
989 unset($params['is_recur']);
991 $params['record_contribution'] = TRUE;
992 $params['contribution_status_id'] = array_search('Failed', CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name'));
994 $form->_contactID
= $this->_individualId
;
996 $form->testSubmit($params);
997 $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId
));
998 $form->testSubmit($params);
999 $membership = $this->callAPISuccessGetSingle('Membership', array('contact_id' => $this->_individualId
));
1000 $this->assertEquals($membership['status_id'], array_search('Pending', CRM_Member_PseudoConstant
::membershipStatus()));
1004 * Get a membership form object.
1006 * We need to instantiate the form to run preprocess, which means we have to trick it about the request method.
1008 * @return \CRM_Member_Form_Membership
1010 protected function getForm() {
1011 $form = new CRM_Member_Form_Membership();
1012 $_SERVER['REQUEST_METHOD'] = 'GET';
1013 $form->controller
= new CRM_Core_Controller();
1020 protected function getBaseSubmitParams() {
1022 'cid' => $this->_individualId
,
1023 'price_set_id' => 0,
1024 'join_date' => date('m/d/Y', time()),
1027 'campaign_id' => '',
1028 // This format reflects the 23 being the organisation & the 25 being the type.
1029 'membership_type_id' => array(23, $this->membershipTypeAnnualFixedID
),
1030 'auto_renew' => '1',
1035 'total_amount' => '77.00',
1036 'financial_type_id' => '2', //Member dues, see data.xml
1037 'soft_credit_type_id' => 11,
1038 'soft_credit_contact_id' => '',
1039 'from_email_address' => '"Demonstrators Anonymous" <info@example.org>',
1040 'receipt_text' => 'Thank you text',
1041 'payment_processor_id' => $this->_paymentProcessorID
,
1042 'credit_card_number' => '4111111111111111',
1044 'credit_card_exp_date' => array(
1046 'Y' => '2019', // TODO: Future proof
1048 'credit_card_type' => 'Visa',
1049 'billing_first_name' => 'Test',
1050 'billing_middlename' => 'Last',
1051 'billing_street_address-5' => '10 Test St',
1052 'billing_city-5' => 'Test',
1053 'billing_state_province_id-5' => '1003',
1054 'billing_postal_code-5' => '90210',
1055 'billing_country_id-5' => '1228',
1056 'send_receipt' => 1,