diff --git a/CRM/Price/BAO/LineItem.php b/CRM/Price/BAO/LineItem.php index b805bc3177a4..efa24b312bac 100644 --- a/CRM/Price/BAO/LineItem.php +++ b/CRM/Price/BAO/LineItem.php @@ -410,7 +410,8 @@ public static function deleteLineItems($entityId, $entityTable) { * * @param bool $update * - * @return void + * @throws \CRM_Core_Exception + * @throws \CiviCRM_API3_Exception */ public static function processPriceSet($entityId, $lineItem, $contributionDetails = NULL, $entityTable = 'civicrm_contribution', $update = FALSE) { if (!$entityId || !is_array($lineItem) diff --git a/tests/phpunit/CRM/Member/BAO/MembershipLogTest.php b/tests/phpunit/CRM/Member/BAO/MembershipLogTest.php index aafd3d03c916..35399fa856b2 100644 --- a/tests/phpunit/CRM/Member/BAO/MembershipLogTest.php +++ b/tests/phpunit/CRM/Member/BAO/MembershipLogTest.php @@ -91,8 +91,7 @@ public function setUp() { 'visibility' => 'Public', 'is_active' => 1, ]; - $ids = []; - $membershipType = CRM_Member_BAO_MembershipType::add($params, $ids); + $membershipType = CRM_Member_BAO_MembershipType::add($params); $this->membershipTypeID = $membershipType->id; $this->membershipStatusID = $this->membershipStatusCreate('test status'); } @@ -105,6 +104,7 @@ public function tearDown() { $this->membershipTypeDelete(['id' => $this->membershipTypeID]); $this->membershipStatusDelete($this->membershipStatusID); $this->contactDelete($this->organizationContactID); + parent::tearDown(); } /** diff --git a/tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php b/tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php index bb0ee159ddf6..e7c4ef15bf72 100644 --- a/tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php +++ b/tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php @@ -114,33 +114,37 @@ public function testDel() { $this->assertEquals(empty($result), TRUE, 'Verify membership status record deletion.'); } + /** + * @throws \CRM_Core_Exception + * @throws \CiviCRM_API3_Exception + */ public function testExpiredDisabled() { - $result = civicrm_api3('MembershipStatus', 'get', [ - 'name' => "Expired", + $this->callAPISuccess('MembershipStatus', 'get', [ + 'name' => 'Expired', 'api.MembershipStatus.create' => ['label' => 'Expiiiired'], ]); // Calling it 'Expiiiired' is OK. - $result = $this->callAPISuccess('job', 'process_membership', []); + $this->callAPISuccess('job', 'process_membership', []); - $result = civicrm_api3('MembershipStatus', 'get', [ - 'name' => "Expired", + $this->callAPISuccess('MembershipStatus', 'get', [ + 'name' => 'Expired', 'api.MembershipStatus.create' => ['is_active' => 0], ]); // Disabling 'Expired' is OK. - $result = $this->callAPISuccess('job', 'process_membership', []); + $this->callAPISuccess('job', 'process_membership', []); - $result = civicrm_api3('MembershipStatus', 'get', [ - 'name' => "Expired", + $this->callAPISuccess('MembershipStatus', 'get', [ + 'name' => 'Expired', 'api.MembershipStatus.delete' => [], ]); // Deleting 'Expired' is OK. - $result = $this->callAPISuccess('job', 'process_membership', []); + $this->callAPISuccess('job', 'process_membership', []); // Put things back like normal - $result = civicrm_api3('MembershipStatus', 'create', [ + $this->callAPISuccess('MembershipStatus', 'create', [ 'name' => 'Expired', 'label' => 'Expired', 'start_event' => 'end_date', diff --git a/tests/phpunit/CRM/Member/BAO/MembershipTest.php b/tests/phpunit/CRM/Member/BAO/MembershipTest.php index b75b27fcf6de..2f8d51741b7f 100644 --- a/tests/phpunit/CRM/Member/BAO/MembershipTest.php +++ b/tests/phpunit/CRM/Member/BAO/MembershipTest.php @@ -17,22 +17,6 @@ class CRM_Member_BAO_MembershipTest extends CiviUnitTestCase { public function setUp() { parent::setUp(); - // FIXME: something NULLs $GLOBALS['_HTML_QuickForm_registered_rules'] when the tests are ran all together - $GLOBALS['_HTML_QuickForm_registered_rules'] = [ - 'required' => ['html_quickform_rule_required', 'HTML/QuickForm/Rule/Required.php'], - 'maxlength' => ['html_quickform_rule_range', 'HTML/QuickForm/Rule/Range.php'], - 'minlength' => ['html_quickform_rule_range', 'HTML/QuickForm/Rule/Range.php'], - 'rangelength' => ['html_quickform_rule_range', 'HTML/QuickForm/Rule/Range.php'], - 'email' => ['html_quickform_rule_email', 'HTML/QuickForm/Rule/Email.php'], - 'regex' => ['html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'], - 'lettersonly' => ['html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'], - 'alphanumeric' => ['html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'], - 'numeric' => ['html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'], - 'nopunctuation' => ['html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'], - 'nonzero' => ['html_quickform_rule_regex', 'HTML/QuickForm/Rule/Regex.php'], - 'callback' => ['html_quickform_rule_callback', 'HTML/QuickForm/Rule/Callback.php'], - 'compare' => ['html_quickform_rule_compare', 'HTML/QuickForm/Rule/Compare.php'], - ]; $this->_contactID = $this->organizationCreate(); $this->_membershipTypeID = $this->membershipTypeCreate(['member_of_contact_id' => $this->_contactID]); @@ -43,6 +27,8 @@ public function setUp() { /** * Tears down the fixture, for example, closes a network connection. * This method is called after a test is executed. + * + * @throws \CRM_Core_Exception */ public function tearDown() { $this->membershipTypeDelete(['id' => $this->_membershipTypeID]); @@ -50,13 +36,19 @@ public function tearDown() { $this->contactDelete($this->_contactID); $this->_contactID = $this->_membershipStatusID = $this->_membershipTypeID = NULL; + $this->quickCleanUpFinancialEntities(); + $this->restoreMembershipTypes(); + parent::tearDown(); } /** * Create membership type using given organization id. + * * @param $organizationId * @param bool $withRelationship + * * @return array|int + * @throws \CRM_Core_Exception */ private function createMembershipType($organizationId, $withRelationship = FALSE) { $membershipType = $this->callAPISuccess('MembershipType', 'create', [ @@ -67,7 +59,7 @@ private function createMembershipType($organizationId, $withRelationship = FALSE 'duration_unit' => "year", 'duration_interval' => 1, 'period_type' => "rolling", - 'name' => "Organiation Membership Type", + 'name' => 'Organiation Membership Type', 'relationship_type_id' => ($withRelationship) ? 5 : NULL, 'relationship_direction' => ($withRelationship) ? 'b_a' : NULL, ]); @@ -466,12 +458,15 @@ public function testRenewMembership() { /** * Renew stale membership. + * + * @throws \CRM_Core_Exception + * @throws \CiviCRM_API3_Exception */ public function testStaleMembership() { $statusId = 3; $contactId = $this->individualCreate(); $joinDate = $startDate = date("Ymd", strtotime(date("Ymd") . " -1 year -15 days")); - $endDate = date("Ymd", strtotime($joinDate . " +1 year -1 day")); + $endDate = date('Ymd', strtotime($joinDate . " +1 year -1 day")); $params = [ 'contact_id' => $contactId, 'membership_type_id' => $this->_membershipTypeID, @@ -511,21 +506,14 @@ public function testStaleMembership() { $membership->id, 'id', 'membership_id', - 'Database checked on membershiplog record.' + 'Database checked on membership log record.' ); - // this is a test and we dont want qfKey generation / validation - // easier to suppress it, than change core code - $config = CRM_Core_Config::singleton(); - $config->keyDisable = TRUE; - - $membershipRenewal = new CRM_Core_Form(); - $membershipRenewal->controller = new CRM_Core_Controller(); list($MembershipRenew) = CRM_Member_BAO_Membership::processMembership( $contactId, $this->_membershipTypeID, FALSE, - $membershipRenewal, + FALSE, NULL, NULL, NULL, @@ -541,7 +529,7 @@ public function testStaleMembership() { $MembershipRenew->id, 'id', 'membership_id', - 'Database checked on membershiplog record.' + 'Database checked on membership log record.' ); $this->membershipDelete($membershipId); @@ -672,7 +660,7 @@ public function testMembershipPaymentForSingleContributionMultipleMembership() { $parentContactId = $this->individualCreate(); $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', [ 'contact_id' => $parentContactId, - 'amount' => 200, + 'amount' => 150, 'frequency_unit' => 'day', 'frequency_interval' => 1, 'installments' => 2, @@ -693,37 +681,15 @@ public function testMembershipPaymentForSingleContributionMultipleMembership() { 'financial_type_id' => $financialTypeId, 'payment_instrument_id' => 'Credit Card', ]); - $contribution = $this->callAPISuccess('contribution', 'create', [ - 'total_amount' => 200, - 'contribution_recur_id' => $contributionRecur['id'], - 'currency' => 'USD', - 'contact_id' => $parentContactId, - 'financial_type_id' => $financialTypeId, - 'contribution_status_id' => 'Completed', - 'skipLineItem' => TRUE, - 'is_recur' => TRUE, - ]); + $params[] = [ - 'contact_id' => $parentContactId, - 'membership_type_id' => $membershipTypeID1, + 'contact_id' => $this->individualCreate(), + 'membership_type_id' => $membershipTypeID2, 'contribution_recur_id' => $contributionRecur['id'], 'join_date' => date('Ymd', time()), 'start_date' => date('Ymd', time()), 'end_date' => date('Ymd', strtotime('+1 year')), - 'skipLineItem' => TRUE, 'source' => 'Payment', - 'line_items' => [ - 'price_field_id' => $priceField['id'], - 'price_field_value_id' => $priceFieldValueId[1], - 'label' => 'Parent', - 'contribution_id' => $contribution['id'], - 'membership_type_id' => $membershipTypeID1, - 'qty' => 1, - 'unit_price' => 100, - 'line_total' => 100, - 'financial_type_id' => $financialTypeId, - 'entity_table' => 'civicrm_membership', - ], ]; $params[] = [ 'contact_id' => $this->individualCreate(), @@ -732,67 +698,99 @@ public function testMembershipPaymentForSingleContributionMultipleMembership() { 'join_date' => date('Ymd', time()), 'start_date' => date('Ymd', time()), 'end_date' => date('Ymd', strtotime('+1 year')), - 'skipLineItem' => TRUE, 'source' => 'Payment', + ]; + + foreach ($params as $key => $param) { + $this->callAPISuccess('membership', 'create', $param); + } + + $contribution = $this->callAPISuccess('Order', 'create', [ + 'total_amount' => 150, + 'contribution_recur_id' => $contributionRecur['id'], + 'currency' => 'USD', + 'contact_id' => $parentContactId, + 'financial_type_id' => $financialTypeId, + 'contribution_status_id' => 'Pending', + 'is_recur' => TRUE, + 'api.Payment.create' => ['total_amount' => 150], 'line_items' => [ - 'price_field_id' => $priceField['id'], - 'price_field_value_id' => $priceFieldValueId[2], - 'label' => 'Child', - 'contribution_id' => $contribution['id'], - 'qty' => 1, - 'unit_price' => 50, - 'line_total' => 50, - 'membership_type_id' => $membershipTypeID2, - 'financial_type_id' => $financialTypeId, - 'entity_table' => 'civicrm_membership', + [ + 'line_item' => [ + 0 => [ + 'price_field_id' => $priceField['id'], + 'price_field_value_id' => $priceFieldValueId[1], + 'label' => 'Parent', + 'membership_type_id' => $membershipTypeID1, + 'qty' => 1, + 'unit_price' => 100, + 'line_total' => 100, + 'financial_type_id' => $financialTypeId, + 'entity_table' => 'civicrm_membership', + ], + 1 => [ + 'price_field_id' => $priceField['id'], + 'price_field_value_id' => $priceFieldValueId[2], + 'label' => 'Child', + 'qty' => 1, + 'unit_price' => 50, + 'line_total' => 50, + 'membership_type_id' => $membershipTypeID2, + 'financial_type_id' => $financialTypeId, + 'entity_table' => 'civicrm_membership', + ], + ], + ], ], - ]; + ]); $params[] = [ - 'contact_id' => $this->individualCreate(), - 'membership_type_id' => $membershipTypeID2, + 'contact_id' => $parentContactId, + 'membership_type_id' => $membershipTypeID1, 'contribution_recur_id' => $contributionRecur['id'], 'join_date' => date('Ymd', time()), 'start_date' => date('Ymd', time()), - 'skipLineItem' => TRUE, 'end_date' => date('Ymd', strtotime('+1 year')), + 'skipLineItem' => TRUE, 'source' => 'Payment', - 'line_items' => [ - 'price_field_id' => $priceField['id'], - 'price_field_value_id' => $priceFieldValueId[2], - 'label' => 'Child', - 'contribution_id' => $contribution['id'], - 'qty' => 1, - 'membership_type_id' => $membershipTypeID2, - 'unit_price' => 50, - 'line_total' => 50, - 'financial_type_id' => $financialTypeId, - 'entity_table' => 'civicrm_membership', - ], ]; - foreach ($params as $key => $param) { - $membership = $this->callAPISuccess('membership', 'create', $param); - $param['line_items']['entity_id'] = $membership['id']; - $memPayments = new CRM_Member_BAO_MembershipPayment(); - $paymentParams = [ - 'membership_id' => $membership['id'], - 'contribution_id' => $contribution['id'], - ]; - $memPayments->copyValues($paymentParams); - $memPayments->save(); - $lineItemBAO = new CRM_Price_BAO_LineItem(); - $lineItemBAO->copyValues($param['line_items']); - $lineItemBAO->save(); - } $this->callAPISuccess('contribution', 'repeattransaction', [ 'original_contribution_id' => $contribution['id'], 'contribution_status_id' => 'Completed', - 'trxn_id' => uniqid(), ]); $this->callAPISuccessGetCount('Contribution', [], 2); + // @todo this fails when run in isolation due some bad stuff in Membership.create $this->callAPISuccessGetCount('LineItem', [], 6); $this->membershipTypeDelete(['id' => $membershipTypeID1]); $this->membershipTypeDelete(['id' => $membershipTypeID2]); + $this->validateAllPayments(); + $this->validateAllContributions(); + } + + /** + * Test the buildMembershipTypeValues function. + */ + public function testBuildMembershipTypeValues() { + $form = new CRM_Core_Form(); + $values = CRM_Member_BAO_Membership::buildMembershipTypeValues($form); + $this->assertEquals([ + 1 => + [ + 'id' => '1', + 'minimum_fee' => '0.000000000', + 'name' => 'General', + 'is_active' => '1', + 'description' => NULL, + 'financial_type_id' => '2', + 'auto_renew' => '0', + 'member_of_contact_id' => $values[1]['member_of_contact_id'], + 'relationship_type_id' => NULL, + 'relationship_direction' => NULL, + 'max_related' => NULL, + 'duration_unit' => 'year', + 'duration_interval' => '1', + ], + ], $values); } /** diff --git a/tests/phpunit/CiviTest/CiviUnitTestCase.php b/tests/phpunit/CiviTest/CiviUnitTestCase.php index 91a9fe1ec36a..933c3fca80ca 100644 --- a/tests/phpunit/CiviTest/CiviUnitTestCase.php +++ b/tests/phpunit/CiviTest/CiviUnitTestCase.php @@ -1805,6 +1805,8 @@ public function quickCleanup($tablesToTruncate, $dropCustomValueTables = FALSE) /** * Clean up financial entities after financial tests (so we remember to get all the tables :-)) + * + * @throws \CRM_Core_Exception */ public function quickCleanUpFinancialEntities() { $tablesToTruncate = [ @@ -1847,6 +1849,9 @@ public function quickCleanUpFinancialEntities() { CRM_Contribute_BAO_Query::$_contribOrSoftCredit = 'only contribs'; } + /** + * Reset the price set config so results exist. + */ public function restoreDefaultPriceSetConfig() { CRM_Core_DAO::executeQuery("DELETE FROM civicrm_price_set WHERE name NOT IN('default_contribution_amount', 'default_membership_type_amount')"); CRM_Core_DAO::executeQuery("UPDATE civicrm_price_set SET id = 1 WHERE name ='default_contribution_amount'"); @@ -1854,6 +1859,20 @@ public function restoreDefaultPriceSetConfig() { CRM_Core_DAO::executeQuery("INSERT INTO `civicrm_price_field_value` (`id`, `price_field_id`, `name`, `label`, `description`, `amount`, `count`, `max_value`, `weight`, `membership_type_id`, `membership_num_terms`, `is_default`, `is_active`, `financial_type_id`, `non_deductible_amount`) VALUES (1, 1, 'contribution_amount', 'Contribution Amount', NULL, '1', NULL, NULL, 1, NULL, NULL, 0, 1, 1, 0.00)"); } + /** + * Recreate default membership types. + */ + public function restoreMembershipTypes() { + CRM_Core_DAO::executeQuery( + "REPLACE INTO civicrm_membership_type + (id, domain_id, name, description, member_of_contact_id, financial_type_id, minimum_fee, duration_unit, duration_interval, period_type, fixed_period_start_day, fixed_period_rollover_day, relationship_type_id, relationship_direction, visibility, weight, is_active) +VALUES + (1, 1, 'General', 'Regular annual membership.', 1, 2, 100.00, 'year', 2, 'rolling', NULL, NULL, 7, 'b_a', 'Public', 1, 1), + (2, 1, 'Student', 'Discount membership for full-time students.', 1, 2, 50.00, 'year', 1, 'rolling', NULL, NULL, NULL, NULL, 'Public', 2, 1), + (3, 1, 'Lifetime', 'Lifetime membership.', 1, 2, 1200.00, 'lifetime', 1, 'rolling', NULL, NULL, 7, 'b_a', 'Admin', 3, 1); + "); + } + /* * Function does a 'Get' on the entity & compares the fields in the Params with those returned * Default behaviour is to also delete the entity