3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
12 use Civi\Api4\MembershipType
;
13 use Civi\Api4\Relationship
;
14 use Civi\Api4\RelationshipType
;
17 * Test APIv3 civicrm_membership functions
19 * @package CiviCRM_APIv3
20 * @subpackage API_Member
24 * Class api_v3_MembershipTest
27 class api_v3_MembershipTest
extends CiviUnitTestCase
{
29 use CRMTraits_Financial_OrderTrait
;
31 protected $_contactID;
32 protected $_membershipID;
33 protected $_membershipID2;
34 protected $_membershipID3;
35 protected $_membershipTypeID;
36 protected $_membershipTypeID2;
37 protected $_membershipStatusID;
44 public function setUp(): void
{
46 $this->_contactID
= $this->individualCreate();
47 $this->_membershipTypeID
= $this->membershipTypeCreate(['member_of_contact_id' => $this->_contactID
]);
48 $this->_membershipTypeID2
= $this->membershipTypeCreate([
49 'period_type' => 'fixed',
51 'fixed_period_start_day' => '301',
53 'fixed_period_rollover_day' => '1111',
54 'name' => 'Another one',
56 $this->_membershipStatusID
= $this->membershipStatusCreate('test status');
58 CRM_Member_PseudoConstant
::membershipStatus(NULL, NULL, 'name', TRUE);
59 CRM_Core_PseudoConstant
::activityType(TRUE, TRUE, TRUE, 'name');
61 $this->_entity
= 'Membership';
63 'contact_id' => $this->_contactID
,
64 'membership_type_id' => $this->_membershipTypeID
,
65 'join_date' => '2009-01-21',
66 'start_date' => '2009-01-21',
67 'end_date' => '2009-12-21',
68 'source' => 'Payment',
70 'status_id' => $this->_membershipStatusID
,
75 * Clean up after tests.
79 public function tearDown(): void
{
80 $this->quickCleanUpFinancialEntities();
81 $this->quickCleanup(['civicrm_uf_match'], TRUE);
82 $this->contactDelete($this->_contactID
);
87 * Test membership deletion.
89 public function testMembershipDelete() {
90 $membershipID = $this->contactMembershipCreate($this->_params
);
91 $this->assertDBRowExist('CRM_Member_DAO_Membership', $membershipID);
93 'id' => $membershipID,
95 $this->callAPIAndDocument('membership', 'delete', $params, __FUNCTION__
, __FILE__
);
96 $this->assertDBRowNotExist('CRM_Member_DAO_Membership', $membershipID);
99 public function testMembershipDeleteEmpty() {
100 $this->callAPIFailure('membership', 'delete', []);
103 public function testMembershipDeleteInvalidID() {
104 $this->callAPIFailure('membership', 'delete', ['id' => 'blah']);
108 * Test membership deletion and with the preserve contribution param.
110 public function testMembershipDeletePreserveContribution() {
112 $membershipID = $this->contactMembershipCreate($this->_params
);
114 $this->assertDBRowExist('CRM_Member_DAO_Membership', $membershipID);
115 $ContributionCreate = $this->callAPISuccess('Contribution', 'create', [
117 'financial_type_id' => "Member Dues",
118 'total_amount' => 100,
119 'contact_id' => $this->_params
['contact_id'],
121 $this->callAPISuccess('MembershipPayment', 'create', [
123 'contribution_id' => $ContributionCreate['values'][0]['id'],
124 'membership_id' => $membershipID,
127 'id' => $membershipID,
128 'preserve_contribution' => 1,
131 'id' => $ContributionCreate['values'][0]['id'],
133 $this->callAPIAndDocument('membership', 'delete', $memParams, __FUNCTION__
, __FILE__
);
134 $this->assertDBRowNotExist('CRM_Member_DAO_Membership', $membershipID);
135 $this->assertDBRowExist('CRM_Contribute_DAO_Contribution', $ContributionCreate['values'][0]['id']);
136 $this->callAPISuccess('Contribution', 'delete', $contribParams);
137 $this->assertDBRowNotExist('CRM_Contribute_DAO_Contribution', $ContributionCreate['values'][0]['id']);
141 * Test Activity creation on cancellation of membership contribution.
143 * @throws \CRM_Core_Exception
144 * @throws \CiviCRM_API3_Exception
146 public function testActivityForCancelledContribution(): void
{
147 $contactId = $this->createLoggedInUser();
149 $this->createContributionAndMembershipOrder();
150 $membershipID = $this->callAPISuccessGetValue('MembershipPayment', ['return' => 'id']);
151 $form = new CRM_Contribute_Form_Contribution();
152 $form->_id
= $this->ids
['Contribution'][0];
154 'total_amount' => 100,
155 'financial_type_id' => 1,
156 'contact_id' => $contactId,
157 'payment_instrument_id' => CRM_Core_PseudoConstant
::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Check'),
158 'contribution_status_id' => 3,
160 CRM_Core_Action
::UPDATE
);
162 $this->callAPISuccessGetSingle('Activity', [
163 'activity_type_id' => 'Membership Signup',
164 'source_record_id' => $membershipID,
165 'subject' => 'General - Payment - Status: Pending',
167 $this->callAPISuccessGetSingle('Activity', [
168 'activity_type_id' => 'Change Membership Status',
169 'source_record_id' => $membershipID,
174 * Test Multiple Membership Status for same contribution id.
176 public function testMultipleMembershipsContribution() {
178 $memStatus = CRM_Member_PseudoConstant
::membershipStatus();
179 // Pending Membership Status
180 $pendingMembershipId = array_search('Pending', $memStatus);
181 // New Membership Status
182 $newMembershipId = array_search('test status', $memStatus);
185 'membership_type_id' => $this->_membershipTypeID
,
186 'source' => 'Webform Payment',
187 'status_id' => $pendingMembershipId,
189 'skipStatusCal' => 1,
193 $contactId1 = $this->individualCreate();
194 $membershipParam['contact_id'] = $contactId1;
195 $membershipID1 = $this->contactMembershipCreate($membershipParam);
197 // Pending Payment Status
198 $ContributionCreate = $this->callAPISuccess('Contribution', 'create', [
199 'financial_type_id' => '1',
200 'total_amount' => 100,
201 'contact_id' => $contactId1,
202 'payment_instrument_id' => CRM_Core_PseudoConstant
::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Check'),
203 'contribution_status_id' => 2,
205 'receive_date' => date('Ymd'),
207 $this->callAPISuccess('MembershipPayment', 'create', [
209 'contribution_id' => $ContributionCreate['id'],
210 'membership_id' => $membershipID1,
214 $contactId2 = $this->individualCreate();
215 $membershipParam['contact_id'] = $contactId2;
216 $membershipID2 = $this->contactMembershipCreate($membershipParam);
217 $this->callAPISuccess('MembershipPayment', 'create', [
219 'contribution_id' => $ContributionCreate['id'],
220 'membership_id' => $membershipID2,
224 $contactId3 = $this->individualCreate();
225 $membershipParam['contact_id'] = $contactId3;
226 $membershipID3 = $this->contactMembershipCreate($membershipParam);
227 $this->callAPISuccess('MembershipPayment', 'create', [
229 'contribution_id' => $ContributionCreate['id'],
230 'membership_id' => $membershipID3,
233 // Change Payment Status to Completed
234 $form = new CRM_Contribute_Form_Contribution();
235 $form->_id
= $ContributionCreate['id'];
236 $params = ['id' => $ContributionCreate['id']];
238 CRM_Contribute_BAO_Contribution
::getValues($params, $values, $ids);
239 $form->_values
= $values;
241 'total_amount' => 100,
242 'financial_type_id' => '1',
243 'contact_id' => $contactId1,
244 'payment_instrument_id' => CRM_Core_PseudoConstant
::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Check'),
245 'contribution_status_id' => 1,
247 CRM_Core_Action
::UPDATE
);
249 // check for Membership 1
250 $params = ['id' => $membershipID1];
251 $membership1 = $this->callAPISuccess('membership', 'get', $params);
252 $result1 = $membership1['values'][$membershipID1];
253 $this->assertEquals($result1['contact_id'], $contactId1);
254 $this->assertEquals($result1['status_id'], $newMembershipId);
256 // check for Membership 2
257 $params = ['id' => $membershipID2];
258 $membership2 = $this->callAPISuccess('membership', 'get', $params);
259 $result2 = $membership2['values'][$membershipID2];
260 $this->assertEquals($result2['contact_id'], $contactId2);
261 $this->assertEquals($result2['status_id'], $newMembershipId);
263 // check for Membership 3
264 $params = ['id' => $membershipID3];
265 $membership3 = $this->callAPISuccess('membership', 'get', $params);
266 $result3 = $membership3['values'][$membershipID3];
267 $this->assertEquals($result3['contact_id'], $contactId3);
268 $this->assertEquals($result3['status_id'], $newMembershipId);
272 * Test membership get.
274 public function testContactMembershipsGet() {
275 $this->_membershipID
= $this->contactMembershipCreate($this->_params
);
276 $this->callAPISuccess('membership', 'get', []);
277 $this->callAPISuccess('Membership', 'Delete', ['id' => $this->_membershipID
]);
281 * Test civicrm_membership_get with params not array.
283 * Gets treated as contact_id, memberships expected.
285 public function testGetWithParamsContactId() {
286 $this->_membershipID
= $this->contactMembershipCreate($this->_params
);
288 'contact_id' => $this->_contactID
,
290 $membership = $this->callAPISuccess('membership', 'get', $params);
292 $result = $membership['values'][$this->_membershipID
];
293 $this->callAPISuccess('Membership', 'Delete', [
294 'id' => $this->_membershipID
,
296 $this->assertEquals($result['contact_id'], $this->_contactID
);
297 $this->assertEquals($result['membership_type_id'], $this->_membershipTypeID
);
298 $this->assertEquals($result['status_id'], $this->_membershipStatusID
);
299 $this->assertEquals($result['join_date'], '2009-01-21');
300 $this->assertEquals($result['start_date'], '2009-01-21');
301 $this->assertEquals($result['end_date'], '2009-12-21');
302 $this->assertEquals($result['source'], 'Payment');
303 $this->assertEquals($result['is_override'], 1);
307 * Test civicrm_membership_get with params not array.
309 * Gets treated as contact_id, memberships expected.
311 public function testGetInSyntax() {
312 $this->_membershipID
= $this->contactMembershipCreate($this->_params
);
313 $this->_membershipID2
= $this->contactMembershipCreate($this->_params
);
314 $this->_membershipID3
= $this->contactMembershipCreate($this->_params
);
316 'id' => ['IN' => [$this->_membershipID
, $this->_membershipID3
]],
318 $membership = $this->callAPISuccess('membership', 'get', $params);
319 $this->assertEquals(2, $membership['count']);
320 $this->assertEquals([$this->_membershipID
, $this->_membershipID3
], array_keys($membership['values']));
322 'id' => ['NOT IN' => [$this->_membershipID
, $this->_membershipID3
]],
324 $membership = $this->callAPISuccess('membership', 'get', $params);
325 $this->assertEquals(1, $membership['count']);
326 $this->assertEquals([$this->_membershipID2
], array_keys($membership['values']));
330 * Test civicrm_membership_get with params not array.
331 * Gets treated as contact_id, memberships expected.
333 public function testGetInSyntaxOnContactID() {
334 $this->_membershipID
= $this->contactMembershipCreate($this->_params
);
335 $contact2 = $this->individualCreate();
336 $contact3 = $this->individualCreate(['first_name' => 'Scout', 'last_name' => 'Canine']);
337 $this->_membershipID2
= $this->contactMembershipCreate(array_merge($this->_params
, ['contact_id' => $contact2]));
338 $this->_membershipID3
= $this->contactMembershipCreate(array_merge($this->_params
, ['contact_id' => $contact3]));
340 'contact_id' => ['IN' => [$this->_contactID
, $contact3]],
342 $membership = $this->callAPISuccess('membership', 'get', $params);
343 $this->assertEquals(2, $membership['count']);
344 $this->assertEquals([$this->_membershipID
, $this->_membershipID3
], array_keys($membership['values']));
346 'contact_id' => ['NOT IN' => [$this->_contactID
, $contact3]],
348 $membership = $this->callAPISuccess('membership', 'get', $params);
349 $this->assertEquals(1, $membership['count']);
350 $this->assertEquals([$this->_membershipID2
], array_keys($membership['values']));
354 * Test civicrm_membership_get with params not array.
356 * Gets treated as contact_id, memberships expected.
358 public function testGetWithParamsMemberShipTypeId() {
359 $this->callAPISuccess($this->_entity
, 'create', $this->_params
);
361 'membership_type_id' => $this->_membershipTypeID
,
363 $membership = $this->callAPISuccess('membership', 'get', $params);
364 $this->callAPISuccess('Membership', 'Delete', [
365 'id' => $membership['id'],
367 $result = $membership['values'][$membership['id']];
368 $this->assertEquals($result['contact_id'], $this->_contactID
);
369 $this->assertEquals($result['membership_type_id'], $this->_membershipTypeID
);
370 $this->assertEquals($result['status_id'], $this->_membershipStatusID
);
371 $this->assertEquals($result['join_date'], '2009-01-21');
372 $this->assertEquals($result['start_date'], '2009-01-21');
373 $this->assertEquals($result['end_date'], '2009-12-21');
374 $this->assertEquals($result['source'], 'Payment');
375 $this->assertEquals($result['is_override'], 1);
376 $this->assertEquals($result['id'], $membership['id']);
380 * Test civicrm_membership_get with params not array.
381 * Gets treated as contact_id, memberships expected.
383 public function testGetWithParamsMemberShipTypeIdContactID() {
384 $params = $this->_params
;
385 $this->callAPISuccess($this->_entity
, 'create', $params);
386 $params['membership_type_id'] = $this->_membershipTypeID2
;
387 $this->callAPISuccess($this->_entity
, 'create', $params);
388 $this->callAPISuccessGetCount('membership', ['contact_id' => $this->_contactID
], 2);
390 'membership_type_id' => $this->_membershipTypeID
,
391 'contact_id' => $this->_contactID
,
393 $result = $this->callAPISuccess('membership', 'getsingle', $params);
394 $this->assertEquals($result['contact_id'], $this->_contactID
);
395 $this->assertEquals($result['membership_type_id'], $this->_membershipTypeID
);
398 'membership_type_id' => $this->_membershipTypeID2
,
399 'contact_id' => $this->_contactID
,
401 $result = $this->callAPISuccess('membership', 'getsingle', $params);
402 $this->assertEquals($result['contact_id'], $this->_contactID
);
403 $this->assertEquals($result['membership_type_id'], $this->_membershipTypeID2
);
407 * Check with complete array + custom field.
409 * Note that the test is written on purpose without any
410 * variables specific to participant so it can be replicated into other entities
411 * and / or moved to the automated test suite
413 public function testGetWithParamsMemberShipIdAndCustom() {
414 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__
, __FILE__
);
416 $params = $this->_params
;
417 $params['custom_' . $ids['custom_field_id']] = "custom string";
419 $result = $this->callAPISuccess($this->_entity
, 'create', $params);
421 $getParams = ['membership_type_id' => $params['membership_type_id']];
422 $check = $this->callAPIAndDocument($this->_entity
, 'get', $getParams, __FUNCTION__
, __FILE__
);
423 $this->assertEquals("custom string", $check['values'][$result['id']]['custom_' . $ids['custom_field_id']], ' in line ' . __LINE__
);
425 $this->callAPISuccess('Membership', 'Delete', [
426 'id' => $result['id'],
431 * Test civicrm_membership_get with proper params.
432 * Memberships expected.
434 public function testGet() {
435 $membershipID = $this->contactMembershipCreate($this->_params
);
437 'contact_id' => $this->_contactID
,
440 $membership = $this->callAPISuccess('membership', 'get', $params);
441 $result = $membership['values'][$membershipID];
442 $this->callAPISuccess('Membership', 'Delete', [
443 'id' => $membership['id'],
445 $this->assertEquals($result['join_date'], '2009-01-21');
446 $this->assertEquals($result['contact_id'], $this->_contactID
);
447 $this->assertEquals($result['membership_type_id'], $this->_membershipTypeID
);
448 $this->assertEquals($result['status_id'], $this->_membershipStatusID
);
450 $this->assertEquals($result['start_date'], '2009-01-21');
451 $this->assertEquals($result['end_date'], '2009-12-21');
452 $this->assertEquals($result['source'], 'Payment');
453 $this->assertEquals($result['is_override'], 1);
457 * Test civicrm_membership_get with proper params.
458 * Memberships expected.
460 public function testGetWithId() {
461 $membershipID = $this->contactMembershipCreate($this->_params
);
463 'contact_id' => $this->_contactID
,
464 'id' => $this->_membershipID
,
467 $result = $this->callAPISuccess('membership', 'get', $params);
468 $this->assertEquals($membershipID, $result['id']);
470 'contact_id' => $this->_contactID
,
471 'membership_id' => $this->_membershipID
,
472 'return' => 'membership_id',
474 $result = $this->callAPISuccess('membership', 'get', $params);
475 $this->assertEquals($membershipID, $result['id']);
479 * Test civicrm_membership_get for only active.
480 * Memberships expected.
482 public function testGetOnlyActive() {
483 $description = "Demonstrates use of 'filter' active_only' param.";
484 $this->_membershipID
= $this->contactMembershipCreate($this->_params
);
486 'contact_id' => $this->_contactID
,
490 $membership = $this->callAPISuccess('membership', 'get', $params);
491 $this->assertEquals($membership['values'][$this->_membershipID
]['status_id'], $this->_membershipStatusID
);
492 $this->assertEquals($membership['values'][$this->_membershipID
]['contact_id'], $this->_contactID
);
494 'contact_id' => $this->_contactID
,
500 $membership = $this->callAPIAndDocument('membership', 'get', $params, __FUNCTION__
, __FILE__
, $description, 'FilterIsCurrent');
501 $this->assertEquals($membership['values'][$this->_membershipID
]['status_id'], $this->_membershipStatusID
);
502 $this->assertEquals($membership['values'][$this->_membershipID
]['contact_id'], $this->_contactID
);
504 $this->callAPISuccess('Membership', 'Delete', ['id' => $this->_membershipID
]);
508 * Test civicrm_membership_get for non exist contact.
511 public function testGetNoContactExists() {
513 'contact_id' => 55555,
516 $membership = $this->callAPISuccess('membership', 'get', $params);
517 $this->assertEquals($membership['count'], 0);
521 * Test civicrm_membership_get with relationship.
524 * @throws \CRM_Core_Exception
526 public function testGetWithRelationship() {
527 $membershipOrgId = $this->organizationCreate(NULL);
528 $memberContactId = $this->individualCreate();
531 'name_a_b' => 'Relation 1',
532 'name_b_a' => 'Relation 2',
533 'description' => 'Testing relationship type',
534 'contact_type_a' => 'Organization',
535 'contact_type_b' => 'Individual',
539 $relTypeID = $this->relationshipTypeCreate($relTypeParams);
542 'name' => 'test General',
543 'duration_unit' => 'year',
544 'duration_interval' => 1,
545 'period_type' => 'rolling',
546 'member_of_contact_id' => $membershipOrgId,
548 'financial_type_id' => 1,
549 'relationship_type_id' => $relTypeID,
550 'relationship_direction' => 'b_a',
553 $memType = $this->callAPISuccess('membership_type', 'create', $params);
556 'contact_id' => $memberContactId,
557 'membership_type_id' => $memType['id'],
558 'join_date' => '2009-01-21',
559 'start_date' => '2009-01-21',
560 'end_date' => '2009-12-21',
561 'source' => 'Payment',
563 'status_id' => $this->_membershipStatusID
,
565 $membershipID = $this->contactMembershipCreate($params);
568 'contact_id' => $memberContactId,
569 'membership_type_id' => $memType['id'],
572 $result = $this->callAPISuccess('membership', 'get', $params);
574 $membership = $result['values'][$membershipID];
575 $this->assertEquals($this->_membershipStatusID
, $membership['status_id']);
576 $this->callAPISuccess('Membership', 'Delete', [
577 'id' => $membership['id'],
579 $this->membershipTypeDelete(['id' => $memType['id']]);
580 $this->relationshipTypeDelete($relTypeID);
581 $this->contactDelete($membershipOrgId);
582 $this->contactDelete($memberContactId);
586 * Test civicrm_membership_create with relationships.
587 * create/get Memberships.
589 * Test suite for CRM-14758: API ( contact, create ) does not always create related membership
590 * and max_related property for Membership_Type and Membership entities
592 * @throws \CRM_Core_Exception
594 public function testCreateWithRelationship() {
595 // Create membership type: inherited through employment, max_related = 2
597 'name_a_b' => 'Employee of',
599 $result = $this->callAPISuccess('relationship_type', 'get', $params);
600 $relationshipTypeId = $result['id'];
601 $membershipOrgId = $this->organizationCreate();
603 'name' => 'Corporate Membership',
604 'duration_unit' => 'year',
605 'duration_interval' => 1,
606 'period_type' => 'rolling',
607 'member_of_contact_id' => $membershipOrgId,
609 'financial_type_id' => 1,
610 'relationship_type_id' => $relationshipTypeId,
611 'relationship_direction' => 'b_a',
615 $result = $this->callAPISuccess('membership_type', 'create', $params);
616 $membershipTypeId = $result['id'];
618 // Create employer and first employee
619 $employerId[0] = $this->organizationCreate([], 1);
620 $memberContactId[0] = $this->individualCreate(['employer_id' => $employerId[0]], 0);
622 // Create organization's membership
624 'contact_id' => $employerId[0],
625 'membership_type_id' => $membershipTypeId,
626 'source' => 'Test suite',
627 'start_date' => date('Y-m-d'),
628 'end_date' => '+1 year',
630 $OrganizationMembershipID = $this->contactMembershipCreate($params);
632 // Check that the employee inherited the membership
634 'contact_id' => $memberContactId[0],
635 'membership_type_id' => $membershipTypeId,
638 $result = $this->callAPISuccess('membership', 'get', $params);
640 $this->assertEquals(1, $result['count']);
641 $result = $result['values'][$result['id']];
642 $this->assertEquals($OrganizationMembershipID, $result['owner_membership_id']);
644 // Create second employee
645 $memberContactId[1] = $this->individualCreate(['employer_id' => $employerId[0]], 1);
647 // Check that the employee inherited the membership
649 'contact_id' => $memberContactId[1],
650 'membership_type_id' => $membershipTypeId,
652 $result = $this->callAPISuccess('membership', 'get', $params);
653 // If it fails here CRM-14758 is not fixed
654 $this->assertEquals(1, $result['count']);
655 $result = $result['values'][$result['id']];
656 $this->assertEquals($OrganizationMembershipID, $result['owner_membership_id']);
658 // Create third employee
659 $memberContactId[2] = $this->individualCreate(['employer_id' => $employerId[0]], 2);
661 // Check that employee does NOT inherit the membership (max_related = 2)
663 'contact_id' => $memberContactId[2],
664 'membership_type_id' => $membershipTypeId,
666 $result = $this->callAPISuccess('membership', 'get', $params);
667 $this->assertEquals(0, $result['count']);
669 // Increase max_related for the employer's membership
671 'id' => $OrganizationMembershipID,
674 $this->callAPISuccess('Membership', 'create', $params);
676 // Check that the employee inherited the membership
678 'contact_id' => $memberContactId[2],
679 'membership_type_id' => $membershipTypeId,
681 $result = $this->callAPISuccess('membership', 'get', $params);
682 $this->assertEquals(1, $result['count']);
683 $result = $result['values'][$result['id']];
684 $this->assertEquals($OrganizationMembershipID, $result['owner_membership_id']);
686 // First employee moves to a new job
687 $employerId[1] = $this->organizationCreate([], 2);
689 'id' => $memberContactId[0],
690 'employer_id' => $employerId[1],
692 $this->callAPISuccess('contact', 'create', $params);
694 // Check that employee does NO LONGER inherit the membership
696 'contact_id' => $memberContactId[0],
697 'membership_type_id' => $membershipTypeId,
699 $result = $this->callAPISuccess('membership', 'get', $params);
700 $this->assertEquals(0, $result['count']);
702 //Create pay_later membership for organization.
703 $employerId[2] = $this->organizationCreate([], 1);
705 'contact_id' => $employerId[2],
706 'membership_type_id' => $membershipTypeId,
707 'source' => 'Test pay later suite',
711 $organizationMembershipID = $this->callAPISuccess('Membership', 'create', $params)['id'];
713 $memberContactId[3] = $this->individualCreate(['employer_id' => $employerId[2]], 0);
714 // Check that the employee inherited the membership
716 'contact_id' => $memberContactId[3],
717 'membership_type_id' => $membershipTypeId,
719 $result = $this->callAPISuccessGetSingle('membership', $params);
720 $this->assertEquals($organizationMembershipID, $result['owner_membership_id']);
722 // Set up params for enable/disable checks
723 $relationship1 = $this->callAPISuccess('relationship', 'get', ['contact_id_a' => $memberContactId[1]]);
725 'contact_id' => $memberContactId[1],
726 'membership_type_id' => $membershipTypeId,
729 // Deactivate relationship using create and assert membership is not inherited
730 $this->callAPISuccess('relationship', 'create', ['id' => $relationship1['id'], 'is_active' => 0]);
731 $result = $this->callAPISuccess('membership', 'get', $params);
732 $this->assertEquals(0, $result['count']);
734 // Re-enable relationship using create and assert membership is inherited
735 $this->callAPISuccess('relationship', 'create', ['id' => $relationship1['id'], 'is_active' => 1]);
736 $result = $this->callAPISuccess('membership', 'get', $params);
737 $this->assertEquals(1, $result['count']);
739 // Deactivate relationship using setvalue and assert membership is not inherited
740 $this->callAPISuccess('relationship', 'setvalue', ['id' => $relationship1['id'], 'field' => 'is_active', 'value' => 0]);
741 $result = $this->callAPISuccess('membership', 'get', $params);
742 $this->assertEquals(0, $result['count']);
744 // Re-enable relationship using setvalue and assert membership is inherited
745 $this->callAPISuccess('relationship', 'setvalue', ['id' => $relationship1['id'], 'field' => 'is_active', 'value' => 1]);
746 $result = $this->callAPISuccess('membership', 'get', $params);
747 $this->assertEquals(1, $result['count']);
749 // Delete relationship and assert membership is not inherited
750 $this->callAPISuccess('relationship', 'delete', ['id' => $relationship1['id']]);
751 $result = $this->callAPISuccess('membership', 'get', $params);
752 $this->assertEquals(0, $result['count']);
754 // Tear down - reverse of creation to be safe
755 $this->contactDelete($memberContactId[2]);
756 $this->contactDelete($memberContactId[1]);
757 $this->contactDelete($memberContactId[0]);
758 $this->contactDelete($employerId[1]);
759 $this->contactDelete($employerId[0]);
760 $this->membershipTypeDelete(['id' => $membershipTypeId]);
761 $this->contactDelete($membershipOrgId);
765 * Test that loops are not created when adding spouse relationships.
767 * This add a test for https://issues.civicrm.org/jira/browse/CRM-4213 in the hope of removing
768 * the buggy fix for that without a resurgence.
770 * @throws \API_Exception
771 * @throws \CRM_Core_Exception
772 * @throws \Civi\API\Exception\UnauthorizedException
774 public function testCreateWithSpouseRelationship() {
775 $relationshipTypeID = RelationshipType
::get()->addSelect('id')->addWhere('name_a_b', '=', 'Spouse of')->execute()->first()['id'];
776 MembershipType
::update()->setValues([
777 'relationship_direction' => ['b_a', 'a_b'],
778 'relationship_type_id' => [$relationshipTypeID, $relationshipTypeID],
780 ->addWhere('name', '=', 'General')
781 ->execute()->first()['id'];
783 $spouse1ID = $this->individualCreate(['first_name' => 'him']);
784 $spouse2ID = $this->individualCreate(['first_name' => 'her']);
785 $spouse3ID = $this->individualCreate(['first_name' => 'they']);
786 $spouse4ID = $this->individualCreate(['first_name' => 'them']);
787 Relationship
::create()->setValues([
788 'contact_id_a' => $spouse1ID,
789 'contact_id_b' => $spouse2ID,
790 'relationship_type_id' => $relationshipTypeID,
793 $this->contactMembershipCreate([
794 'contact_id' => $spouse1ID,
795 'start_date' => date('Y-m-d'),
796 'end_date' => '+1 year',
799 $this->callAPISuccessGetSingle('Membership', [
800 'contact_id' => $spouse2ID,
801 'membership_type_id' => 'General',
804 $this->callAPISuccessGetSingle('Membership', [
805 'contact_id' => $spouse1ID,
806 'membership_type_id' => 'General',
808 // Add another Spouse
809 Relationship
::create()->setValues([
810 'contact_id_a' => $spouse3ID,
811 'contact_id_b' => $spouse1ID,
812 'relationship_type_id' => $relationshipTypeID,
814 $this->callAPISuccessGetSingle('Membership', [
815 'contact_id' => $spouse3ID,
816 'membership_type_id' => 'General',
818 $this->callAPISuccessGetCount('Membership', [], 3);
819 Relationship
::create()->setValues([
820 'contact_id_a' => $spouse1ID,
821 'contact_id_b' => $spouse4ID,
822 'relationship_type_id' => $relationshipTypeID,
825 $this->callAPISuccessGetSingle('Membership', [
826 'contact_id' => $spouse4ID,
827 'membership_type_id' => 'General',
830 $this->callAPISuccessGetCount('Membership', [], 4);
834 * We are checking for no e-notices + only id & end_date returned
836 * @throws \CRM_Core_Exception
838 public function testMembershipGetWithReturn() {
839 $this->contactMembershipCreate($this->_params
);
840 $result = $this->callAPISuccess('membership', 'get', ['return' => 'end_date']);
841 foreach ($result['values'] as $membership) {
842 $this->assertEquals(['id', 'end_date'], array_keys($membership));
846 ///////////////// civicrm_membership_create methods
849 * Test civicrm_contact_memberships_create with empty params.
852 public function testCreateWithEmptyParams() {
854 $this->callAPIFailure('membership', 'create', $params);
858 * If is_overide is passed in status must also be passed in.
860 public function testCreateOverrideNoStatus() {
861 $params = $this->_params
;
862 unset($params['status_id']);
863 $this->callAPIFailure('membership', 'create', $params);
866 public function testMembershipCreateMissingRequired() {
868 'membership_type_id' => '1',
869 'join_date' => '2006-01-21',
870 'start_date' => '2006-01-21',
871 'end_date' => '2006-12-21',
872 'source' => 'Payment',
876 $this->callAPIFailure('membership', 'create', $params);
879 public function testMembershipCreate() {
881 'contact_id' => $this->_contactID
,
882 'membership_type_id' => $this->_membershipTypeID
,
883 'join_date' => '2006-01-21',
884 'start_date' => '2006-01-21',
885 'end_date' => '2006-12-21',
886 'source' => 'Payment',
888 'status_id' => $this->_membershipStatusID
,
891 $result = $this->callAPIAndDocument('membership', 'create', $params, __FUNCTION__
, __FILE__
);
892 $this->getAndCheck($params, $result['id'], $this->_entity
);
893 $this->assertNotNull($result['id']);
894 $this->assertEquals($this->_contactID
, $result['values'][$result['id']]['contact_id'], " in line " . __LINE__
);
895 $this->assertEquals($result['id'], $result['values'][$result['id']]['id'], " in line " . __LINE__
);
899 * Check for useful message if contact doesn't exist
901 public function testMembershipCreateWithInvalidContact() {
904 'membership_type_id' => $this->_membershipTypeID
,
905 'join_date' => '2006-01-21',
906 'start_date' => '2006-01-21',
907 'end_date' => '2006-12-21',
908 'source' => 'Payment',
910 'status_id' => $this->_membershipStatusID
,
913 $this->callAPIFailure('membership', 'create', $params,
914 'contact_id is not valid : 999'
918 public function testMembershipCreateWithInvalidStatus() {
919 $params = $this->_params
;
920 $params['status_id'] = 999;
921 $this->callAPIFailure('membership', 'create', $params,
922 "'999' is not a valid option for field status_id"
926 public function testMembershipCreateWithInvalidType() {
927 $params = $this->_params
;
928 $params['membership_type_id'] = 999;
930 $this->callAPIFailure('membership', 'create', $params,
931 "'999' is not a valid option for field membership_type_id"
936 * Check with complete array + custom field
937 * Note that the test is written on purpose without any
938 * variables specific to participant so it can be replicated into other entities
939 * and / or moved to the automated test suite
941 public function testCreateWithCustom() {
942 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__
, __FILE__
);
944 $params = $this->_params
;
945 $params['custom_' . $ids['custom_field_id']] = "custom string";
947 $result = $this->callAPIAndDocument($this->_entity
, 'create', $params, __FUNCTION__
, __FILE__
, NULL, 'CreateWithCustomData');
948 $check = $this->callAPISuccess($this->_entity
, 'get', [
949 'id' => $result['id'],
950 'contact_id' => $this->_contactID
,
952 $this->assertEquals("custom string", $check['values'][$result['id']]['custom_' . $ids['custom_field_id']], ' in line ' . __LINE__
);
956 * Search on custom field value.
958 public function testSearchWithCustomDataCRM16036() {
959 // Create a custom field on membership
960 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__
, __FILE__
);
962 // Create a new membership, but don't assign anything to the custom field.
963 $params = $this->_params
;
964 $result = $this->callAPIAndDocument(
971 'SearchWithCustomData');
973 // search memberships with CRM-16036 as custom field value.
974 // Since we did not touch the custom field of any membership,
975 // this should not return any results.
976 $check = $this->callAPISuccess($this->_entity
, 'get', [
977 'custom_' . $ids['custom_field_id'] => "CRM-16036",
981 $this->callAPISuccess($this->_entity
, 'delete', [
982 'id' => $result['id'],
986 $this->assertEquals(0, $check['count']);
990 * Test civicrm_contact_memberships_create with membership id (edit
994 public function testMembershipCreateWithId() {
995 $membershipID = $this->contactMembershipCreate($this->_params
);
997 'id' => $membershipID,
998 'contact_id' => $this->_contactID
,
999 'membership_type_id' => $this->_membershipTypeID
,
1000 'join_date' => '2006-01-21',
1001 'start_date' => '2006-01-21',
1002 'end_date' => '2006-12-21',
1003 'source' => 'Payment',
1005 'status_id' => $this->_membershipStatusID
,
1008 $result = $this->callAPISuccess('membership', 'create', $params);
1010 //Update Status and check activities created.
1012 'id' => $result['id'],
1013 'status_id' => CRM_Core_PseudoConstant
::getKey('CRM_Member_BAO_Membership', 'status_id', 'Cancelled'),
1015 $this->callAPISuccess('Membership', 'create', $updateStatus);
1016 $activities = CRM_Activity_BAO_Activity
::getContactActivity($this->_contactID
);
1017 $this->assertEquals(2, count($activities));
1018 $activityNames = array_flip(CRM_Utils_Array
::collect('activity_name', $activities));
1019 $this->assertArrayHasKey('Membership Signup', $activityNames);
1020 $this->assertArrayHasKey('Change Membership Status', $activityNames);
1022 $this->callAPISuccess('Membership', 'Delete', [
1023 'id' => $result['id'],
1025 $this->assertEquals($result['id'], $membershipID, "in line " . __LINE__
);
1029 * Test civicrm_contact_memberships_create with membership id (edit
1033 public function testMembershipCreateUpdateWithIdNoContact() {
1034 $membershipID = $this->contactMembershipCreate($this->_params
);
1036 'id' => $membershipID,
1037 'membership_type_id' => $this->_membershipTypeID
,
1038 'contact_id' => $this->_contactID
,
1039 'join_date' => '2006-01-21',
1040 'start_date' => '2006-01-21',
1041 'end_date' => '2006-12-21',
1042 'source' => 'Payment',
1044 'status_id' => $this->_membershipStatusID
,
1047 $result = $this->callAPISuccess('membership', 'create', $params);
1048 $this->callAPISuccess('Membership', 'Delete', [
1049 'id' => $result['id'],
1052 $this->assertEquals($result['id'], $membershipID, "in line " . __LINE__
);
1056 * Test civicrm_contact_memberships_create with membership id (edit
1060 public function testMembershipCreateUpdateWithIdNoDates() {
1061 $membershipID = $this->contactMembershipCreate($this->_params
);
1063 'id' => $membershipID,
1064 'contact_id' => $this->_contactID
,
1065 'membership_type_id' => $this->_membershipTypeID
,
1066 'source' => 'Payment',
1068 'status_id' => $this->_membershipStatusID
,
1071 $result = $this->callAPISuccess('membership', 'create', $params);
1072 $this->callAPISuccess('Membership', 'Delete', [
1073 'id' => $result['id'],
1075 $this->assertEquals($result['id'], $membershipID, "in line " . __LINE__
);
1079 * Test civicrm_contact_memberships_create with membership id (edit
1083 public function testMembershipCreateUpdateWithIdNoDatesNoType() {
1084 $membershipID = $this->contactMembershipCreate($this->_params
);
1086 'id' => $membershipID,
1087 'source' => 'not much here',
1088 'contact_id' => $this->_contactID
,
1090 'status_id' => $this->_membershipStatusID
,
1093 $result = $this->callAPISuccess('membership', 'create', $params);
1094 $this->callAPISuccess('Membership', 'Delete', [
1095 'id' => $result['id'],
1097 $this->assertEquals($result['id'], $membershipID, "in line " . __LINE__
);
1101 * Test civicrm_contact_memberships_create with membership id (edit
1105 public function testMembershipCreateUpdateWithIDAndSource() {
1106 $membershipID = $this->contactMembershipCreate($this->_params
);
1108 'id' => $membershipID,
1109 'source' => 'changed',
1110 'contact_id' => $this->_contactID
,
1111 'status_id' => $this->_membershipStatusID
,
1112 'membership_type_id' => $this->_membershipTypeID
,
1113 'skipStatusCal' => 1,
1115 $result = $this->callAPISuccess('membership', 'create', $params);
1116 $this->assertEquals($result['id'], $membershipID, "in line " . __LINE__
);
1117 $this->callAPISuccess('Membership', 'Delete', [
1118 'id' => $result['id'],
1123 * Change custom field using update.
1125 public function testUpdateWithCustom() {
1126 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__
, __FILE__
);
1128 $params = $this->_params
;
1129 $params['custom_' . $ids['custom_field_id']] = "custom string";
1130 $result = $this->callAPIAndDocument($this->_entity
, 'create', $params, __FUNCTION__
, __FILE__
, NULL, 'UpdateCustomData');
1131 $result = $this->callAPISuccess($this->_entity
, 'create', [
1132 'id' => $result['id'],
1133 'custom_' . $ids['custom_field_id'] => "new custom",
1135 $check = $this->callAPISuccess($this->_entity
, 'get', [
1136 'id' => $result['id'],
1137 'contact_id' => $this->_contactID
,
1140 $this->assertEquals("new custom", $check['values'][$result['id']]['custom_' . $ids['custom_field_id']], ' in line ' . __LINE__
);
1141 $this->callAPISuccess('Membership', 'Delete', [
1142 'id' => $check['id'],
1145 $this->customFieldDelete($ids['custom_field_id']);
1146 $this->customGroupDelete($ids['custom_group_id']);
1150 * per CRM-15746 check that the id can be altered in an update hook
1152 public function testMembershipUpdateCreateHookCRM15746() {
1153 $this->hookClass
->setHook('civicrm_pre', [$this, 'hook_civicrm_pre_update_create_membership']);
1154 $result = $this->callAPISuccess('membership', 'create', $this->_params
);
1155 $this->callAPISuccess('membership', 'create', ['id' => $result['id'], 'end_date' => '1 year ago']);
1156 $this->callAPISuccessGetCount('membership', [], 2);
1157 $this->hookClass
->reset();
1158 $this->callAPISuccess('membership', 'create', ['id' => $result['id'], 'end_date' => '1 year ago']);
1159 $this->callAPISuccessGetCount('membership', [], 2);
1163 * Custom hook for update membership.
1166 * @param object $objectName
1168 * @param array $params
1170 * @throws \Exception
1172 public function hook_civicrm_pre_update_create_membership($op, $objectName, $id, &$params) {
1173 if ($objectName === 'Membership' && $op === 'edit') {
1174 $existingMembership = $this->callAPISuccessGetSingle('membership', ['id' => $params['id']]);
1175 unset($params['id'], $params['membership_id']);
1176 $params['join_date'] = $params['membership_start_date'] = $params['start_date'] = date('Ymd000000', strtotime($existingMembership['start_date']));
1177 $params = array_merge($existingMembership, $params);
1178 $params['id'] = NULL;
1183 * Test civicrm_contact_memberships_create Invalid membership data.
1186 public function testMembershipCreateInvalidMemData() {
1187 //membership_contact_id as string
1189 'membership_contact_id' => 'Invalid',
1190 'membership_type_id' => $this->_membershipTypeID
,
1191 'join_date' => '2011-01-21',
1192 'start_date' => '2010-01-21',
1193 'end_date' => '2008-12-21',
1194 'source' => 'Payment',
1196 'status_id' => $this->_membershipStatusID
,
1199 $this->callAPIFailure('membership', 'create', $params);
1201 //membership_contact_id which is no in contact table
1202 $params['membership_contact_id'] = 999;
1203 $this->callAPIFailure('membership', 'create', $params);
1206 unset($params['membership_contact_id']);
1207 $params['join_date'] = "invalid";
1208 $this->callAPIFailure('Membership', 'Create', $params);
1212 * Test civicrm_contact_memberships_create with membership_contact_id
1216 public function testMembershipCreateWithMemContact() {
1218 'membership_contact_id' => $this->_contactID
,
1219 'membership_type_id' => $this->_membershipTypeID
,
1220 'join_date' => '2011-01-21',
1221 'start_date' => '2010-01-21',
1222 'end_date' => '2008-12-21',
1223 'source' => 'Payment',
1225 'status_id' => $this->_membershipStatusID
,
1228 $result = $this->callAPISuccess('membership', 'create', $params);
1230 $this->callAPISuccess('Membership', 'Delete', [
1231 'id' => $result['id'],
1236 * Test civicrm_contact_memberships_create with membership_contact_id
1240 public function testMembershipCreateValidMembershipTypeString() {
1242 'membership_contact_id' => $this->_contactID
,
1243 'membership_type_id' => 'General',
1244 'join_date' => '2011-01-21',
1245 'start_date' => '2010-01-21',
1246 'end_date' => '2008-12-21',
1247 'source' => 'Payment',
1249 'status_id' => $this->_membershipStatusID
,
1252 $result = $this->callAPISuccess('membership', 'create', $params);
1253 $this->assertEquals($this->_membershipTypeID
, $result['values'][$result['id']]['membership_type_id']);
1254 $this->callAPISuccess('Membership', 'Delete', [
1255 'id' => $result['id'],
1260 * Test civicrm_contact_memberships_create with membership_contact_id
1264 public function testMembershipCreateInValidMembershipTypeString() {
1266 'membership_contact_id' => $this->_contactID
,
1267 'membership_type_id' => 'invalid',
1268 'join_date' => '2011-01-21',
1269 'start_date' => '2010-01-21',
1270 'end_date' => '2008-12-21',
1271 'source' => 'Payment',
1273 'status_id' => $this->_membershipStatusID
,
1276 $this->callAPIFailure('membership', 'create', $params);
1280 * Test that if membership join date is not set it defaults to today.
1282 public function testEmptyJoinDate() {
1283 unset($this->_params
['join_date'], $this->_params
['is_override']);
1284 $result = $this->callAPISuccess($this->_entity
, 'create', $this->_params
);
1285 $result = $this->callAPISuccess($this->_entity
, 'getsingle', ['id' => $result['id']]);
1286 $this->assertEquals(date('Y-m-d', strtotime('now')), $result['join_date']);
1287 $this->assertEquals('2009-01-21', $result['start_date']);
1288 $this->assertEquals('2009-12-21', $result['end_date']);
1292 * Test that if membership start date is not set it defaults to correct end date.
1295 public function testEmptyStartDateFixed() {
1296 unset($this->_params
['start_date'], $this->_params
['is_override']);
1297 $this->_params
['membership_type_id'] = $this->_membershipTypeID2
;
1298 $result = $this->callAPISuccess($this->_entity
, 'create', $this->_params
);
1299 $result = $this->callAPISuccess($this->_entity
, 'getsingle', ['id' => $result['id']]);
1300 $this->assertEquals('2009-01-21', $result['join_date']);
1301 $this->assertEquals('2008-03-01', $result['start_date']);
1302 $this->assertEquals('2009-12-21', $result['end_date']);
1306 * Test that if membership start date is not set it defaults to correct end date
1309 public function testEmptyStartEndDateFixedOneYear() {
1310 unset($this->_params
['start_date'], $this->_params
['is_override'], $this->_params
['end_date']);
1311 $this->callAPISuccess('membership_type', 'create', ['id' => $this->_membershipTypeID2
, 'duration_interval' => 1]);
1312 $this->_params
['membership_type_id'] = $this->_membershipTypeID2
;
1313 $result = $this->callAPISuccess($this->_entity
, 'create', $this->_params
);
1314 $result = $this->callAPISuccess($this->_entity
, 'getsingle', ['id' => $result['id']]);
1315 $this->assertEquals('2009-01-21', $result['join_date']);
1316 $this->assertEquals('2008-03-01', $result['start_date']);
1317 $this->assertEquals('2010-02-28', $result['end_date']);
1321 * Test that if membership start date is not set it defaults to correct end date for fixed multi year memberships.
1323 public function testEmptyStartEndDateFixedMultiYear() {
1324 unset($this->_params
['start_date'], $this->_params
['is_override'], $this->_params
['end_date']);
1325 $this->callAPISuccess('membership_type', 'create', ['id' => $this->_membershipTypeID2
, 'duration_interval' => 5]);
1326 $this->_params
['membership_type_id'] = $this->_membershipTypeID2
;
1327 $result = $this->callAPISuccess($this->_entity
, 'create', $this->_params
);
1328 $result = $this->callAPISuccess($this->_entity
, 'getsingle', ['id' => $result['id']]);
1329 $this->assertEquals('2009-01-21', $result['join_date']);
1330 $this->assertEquals('2008-03-01', $result['start_date']);
1331 $this->assertEquals('2014-02-28', $result['end_date']);
1335 * CRM-18503 - Test membership join date is correctly set for fixed memberships.
1337 * @throws \CRM_Core_Exception|\CiviCRM_API3_Exception
1339 public function testMembershipJoinDateFixed() {
1340 $memStatus = CRM_Member_PseudoConstant
::membershipStatus();
1341 // Update the fixed membership type to 1 year duration.
1342 $this->callAPISuccess('membership_type', 'create', ['id' => $this->_membershipTypeID2
, 'duration_interval' => 1]);
1343 $contactId = $this->createLoggedInUser();
1344 // Create membership with 'Pending' status.
1346 'contact_id' => $contactId,
1347 'membership_type_id' => $this->_membershipTypeID2
,
1348 'source' => 'test membership',
1349 'is_pay_later' => 0,
1350 'status_id' => 'Pending',
1351 'skipStatusCal' => 1,
1352 'is_for_organization' => 1,
1354 $membership = $this->callAPISuccess('Membership', 'create', $params);
1356 // Update membership to 'Completed' and check the dates.
1358 'id' => $membership['id'],
1359 'contact_id' => $contactId,
1361 'membership_type_id' => $this->_membershipTypeID2
,
1363 'status_id' => 'New',
1365 $result = $this->callAPISuccess('Membership', 'create', $memParams);
1367 // Extend duration interval if join_date exceeds the rollover period.
1368 $joinDate = date('Y-m-d');
1370 $startDate = date('Y-m-d', strtotime(date('Y-03-01')));
1372 if (strtotime($startDate) > time()) {
1374 $startDate = date('Y-m-d', strtotime(date('Y-03-01') . '- 1 year'));
1376 $membershipTypeDetails = CRM_Member_BAO_MembershipType
::getMembershipType($this->_membershipTypeID2
);
1377 $fixedPeriodRollover = CRM_Member_BAO_MembershipType
::isDuringFixedAnnualRolloverPeriod($joinDate, $membershipTypeDetails, $year, $startDate);
1379 if ($fixedPeriodRollover && $rollOver) {
1384 'join_date' => date('Ymd'),
1385 'start_date' => str_replace('-', '', $startDate),
1386 'end_date' => date('Ymd', strtotime(date('Y-03-01') . "+ {$y} year - 1 day")),
1388 foreach ($result['values'] as $values) {
1389 foreach ($expectedDates as $date => $val) {
1390 $this->assertEquals($val, $values[$date], "Failed asserting {$date} values");
1396 * Test correct end and start dates are calculated for fixed multi year memberships.
1398 * The empty start date is calculated to be the start_date (1 Jan prior to the join_date - so 1 Jan 15)
1400 * In this set our start date is after the start day and before the rollover day so we don't get an extra year
1401 * and we end one day before the rollover day. Start day is 1 Jan so we end on 31 Dec
1402 * and we add on 4 years rather than 5 because we are not after the rollover day - so we calculate 31 Dec 2019
1404 public function testFixedMultiYearDateSetTwoEmptyStartEndDate() {
1405 unset($this->_params
['start_date'], $this->_params
['is_override'], $this->_params
['end_date']);
1407 $this->callAPISuccess('membership_type', 'create', [
1408 'id' => $this->_membershipTypeID2
,
1409 'duration_interval' => 5,
1411 'fixed_period_start_day' => '101',
1413 'fixed_period_rollover_day' => '1101',
1415 $this->_params
['membership_type_id'] = $this->_membershipTypeID2
;
1417 'join_date' => '28-Jan 2015',
1419 $result = $this->callAPISuccess($this->_entity
, 'create', array_merge($this->_params
, $dates));
1420 $result = $this->callAPISuccess($this->_entity
, 'getsingle', ['id' => $result['id']]);
1421 $this->assertEquals('2015-01-28', $result['join_date']);
1422 $this->assertEquals('2015-01-01', $result['start_date']);
1423 $this->assertEquals('2019-12-31', $result['end_date']);
1427 * Test that correct end date is calculated for fixed multi year memberships and start date is not changed.
1429 * In this set our start date is after the start day and before the rollover day so we don't get an extra year
1430 * and we end one day before the rollover day. Start day is 1 Jan so we end on 31 Dec
1431 * and we add on 4 years rather than 5 because we are not after the rollover day - so we calculate 31 Dec 2019
1433 public function testFixedMultiYearDateSetTwoEmptyEndDate() {
1434 unset($this->_params
['start_date'], $this->_params
['is_override'], $this->_params
['end_date']);
1436 $this->callAPISuccess('membership_type', 'create', [
1437 'id' => $this->_membershipTypeID2
,
1438 'duration_interval' => 5,
1440 'fixed_period_start_day' => '101',
1442 'fixed_period_rollover_day' => '1101',
1444 $this->_params
['membership_type_id'] = $this->_membershipTypeID2
;
1446 'start_date' => '28-Jan 2015',
1447 'join_date' => '28-Jan 2015',
1449 $result = $this->callAPISuccess($this->_entity
, 'create', array_merge($this->_params
, $dates));
1450 $result = $this->callAPISuccess($this->_entity
, 'getsingle', ['id' => $result['id']]);
1451 $this->assertEquals('2015-01-28', $result['join_date']);
1452 $this->assertEquals('2015-01-28', $result['start_date']);
1453 $this->assertEquals('2019-12-31', $result['end_date']);
1457 * Test correct end and start dates are calculated for fixed multi year memberships.
1459 * The empty start date is calculated to be the start_date (1 Jan prior to the join_date - so 1 Jan 15)
1461 * In this set our start date is after the start day and before the rollover day so we don't get an extra year
1462 * and we end one day before the rollover day. Start day is 1 Jan so we end on 31 Dec
1463 * and we add on <1 years rather than > 1 because we are not after the rollover day - so we calculate 31 Dec 2015
1465 public function testFixedSingleYearDateSetTwoEmptyStartEndDate() {
1466 unset($this->_params
['start_date'], $this->_params
['is_override'], $this->_params
['end_date']);
1468 $this->callAPISuccess('membership_type', 'create', [
1469 'id' => $this->_membershipTypeID2
,
1470 'duration_interval' => 1,
1472 'fixed_period_start_day' => '101',
1474 'fixed_period_rollover_day' => '1101',
1476 $this->_params
['membership_type_id'] = $this->_membershipTypeID2
;
1478 'join_date' => '28-Jan 2015',
1480 $result = $this->callAPISuccess($this->_entity
, 'create', array_merge($this->_params
, $dates));
1481 $result = $this->callAPISuccess($this->_entity
, 'getsingle', ['id' => $result['id']]);
1482 $this->assertEquals('2015-01-28', $result['join_date']);
1483 $this->assertEquals('2015-01-01', $result['start_date']);
1484 $this->assertEquals('2015-12-31', $result['end_date']);
1488 * Test correct end date for fixed single year memberships is calculated and start_date is not changed.
1490 * In this set our start date is after the start day and before the rollover day so we don't get an extra year
1491 * and we end one day before the rollover day. Start day is 1 Jan so we end on 31 Dec
1492 * and we add on <1 years rather than > 1 because we are not after the rollover day - so we calculate 31 Dec 2015
1494 public function testFixedSingleYearDateSetTwoEmptyEndDate() {
1495 unset($this->_params
['start_date'], $this->_params
['is_override'], $this->_params
['end_date']);
1497 $this->callAPISuccess('membership_type', 'create', [
1498 'id' => $this->_membershipTypeID2
,
1499 'duration_interval' => 1,
1501 'fixed_period_start_day' => '101',
1503 'fixed_period_rollover_day' => '1101',
1505 $this->_params
['membership_type_id'] = $this->_membershipTypeID2
;
1507 'start_date' => '28-Jan 2015',
1508 'join_date' => '28-Jan 2015',
1510 $result = $this->callAPISuccess($this->_entity
, 'create', array_merge($this->_params
, $dates));
1511 $result = $this->callAPISuccess($this->_entity
, 'getsingle', ['id' => $result['id']]);
1512 $this->assertEquals('2015-01-28', $result['join_date']);
1513 $this->assertEquals('2015-01-28', $result['start_date']);
1514 $this->assertEquals('2015-12-31', $result['end_date']);
1518 * Test that correct end date is calculated for fixed multi year memberships and start date is not changed.
1520 * In this set our start date is after the start day and after the rollover day so we do get an extra year
1521 * and we end one day before the rollover day. Start day is 1 Nov so we end on 31 Oct
1522 * and we add on 1 year we are after the rollover day - so we calculate 31 Oct 2016
1524 public function testFixedSingleYearDateSetThreeEmptyEndDate() {
1525 unset($this->_params
['start_date'], $this->_params
['is_override'], $this->_params
['end_date']);
1527 $this->callAPISuccess('membership_type', 'create', [
1528 'id' => $this->_membershipTypeID2
,
1529 'duration_interval' => 1,
1531 'fixed_period_start_day' => '1101',
1533 'fixed_period_rollover_day' => '101',
1535 $this->_params
['membership_type_id'] = $this->_membershipTypeID2
;
1537 'start_date' => '28-Jan 2015',
1538 'join_date' => '28-Jan 2015',
1540 $result = $this->callAPISuccess($this->_entity
, 'create', array_merge($this->_params
, $dates));
1541 $result = $this->callAPISuccess($this->_entity
, 'getsingle', ['id' => $result['id']]);
1542 $this->assertEquals('2015-01-28', $result['join_date']);
1543 $this->assertEquals('2015-01-28', $result['start_date']);
1544 $this->assertEquals('2016-10-31', $result['end_date']);
1548 * Test correct end and start dates are calculated for fixed multi year memberships.
1550 * The empty start date is calculated to be the start_date (1 Nov prior to the join_date - so 1 Nov 14)
1552 * In this set our start date is after the start day and after the rollover day so we do get an extra year
1553 * and we end one day before the rollover day. Start day is 1 Nov so we end on 31 Oct
1554 * and we add on 1 year we are after the rollover day - so we calculate 31 Oct 2016
1556 public function testFixedSingleYearDateSetThreeEmptyStartEndDate() {
1557 unset($this->_params
['start_date'], $this->_params
['is_override'], $this->_params
['end_date']);
1559 $this->callAPISuccess('membership_type', 'create', [
1560 'id' => $this->_membershipTypeID2
,
1561 'duration_interval' => 1,
1563 'fixed_period_start_day' => '1101',
1565 'fixed_period_rollover_day' => '101',
1567 $this->_params
['membership_type_id'] = $this->_membershipTypeID2
;
1569 'join_date' => '28-Jan 2015',
1571 $result = $this->callAPISuccess($this->_entity
, 'create', array_merge($this->_params
, $dates));
1572 $result = $this->callAPISuccess($this->_entity
, 'getsingle', ['id' => $result['id']]);
1573 $this->assertEquals('2015-01-28', $result['join_date']);
1574 $this->assertEquals('2014-11-01', $result['start_date']);
1575 $this->assertEquals('2016-10-31', $result['end_date']);
1579 * Test that correct end date is calculated for fixed multi year memberships and start date is not changed.
1581 * In this set our start date is after the start day and after the rollover day so we do get an extra year
1582 * and we end one day before the rollover day. Start day is 1 Nov so we end on 31 Oct
1583 * and we add on 5 years we are after the rollover day - so we calculate 31 Oct 2020
1585 public function testFixedMultiYearDateSetThreeEmptyEndDate() {
1586 unset($this->_params
['start_date'], $this->_params
['is_override'], $this->_params
['end_date']);
1588 $this->callAPISuccess('membership_type', 'create', [
1589 'id' => $this->_membershipTypeID2
,
1590 'duration_interval' => 5,
1592 'fixed_period_start_day' => '1101',
1594 'fixed_period_rollover_day' => '101',
1596 $this->_params
['membership_type_id'] = $this->_membershipTypeID2
;
1598 'start_date' => '28-Jan 2015',
1599 'join_date' => '28-Jan 2015',
1601 $result = $this->callAPISuccess($this->_entity
, 'create', array_merge($this->_params
, $dates));
1602 $result = $this->callAPISuccess($this->_entity
, 'getsingle', ['id' => $result['id']]);
1603 $this->assertEquals('2015-01-28', $result['join_date']);
1604 $this->assertEquals('2015-01-28', $result['start_date']);
1605 $this->assertEquals('2020-10-31', $result['end_date']);
1609 * Test correct end and start dates are calculated for fixed multi year memberships.
1611 * The empty start date is calculated to be the start_date (1 Nov prior to the join_date - so 1 Nov 14)
1613 * The empty start date is calculated to be the start_date (1 Nov prior to the join_date - so 1 Nov 14)
1614 * In this set our join date is after the start day and after the rollover day so we do get an extra year
1615 * and we end one day before the rollover day. Start day is 1 Nov so we end on 31 Oct
1616 * and we add on 5 years we are after the rollover day - so we calculate 31 Oct 2020
1618 public function testFixedMultiYearDateSetThreeEmptyStartEndDate() {
1619 unset($this->_params
['start_date'], $this->_params
['is_override'], $this->_params
['end_date']);
1621 $this->callAPISuccess('membership_type', 'create', [
1622 'id' => $this->_membershipTypeID2
,
1623 'duration_interval' => 5,
1625 'fixed_period_start_day' => '1101',
1627 'fixed_period_rollover_day' => '101',
1629 $this->_params
['membership_type_id'] = $this->_membershipTypeID2
;
1631 'join_date' => '28-Jan 2015',
1633 $result = $this->callAPISuccess($this->_entity
, 'create', array_merge($this->_params
, $dates));
1634 $result = $this->callAPISuccess($this->_entity
, 'getsingle', ['id' => $result['id']]);
1635 $this->assertEquals('2015-01-28', $result['join_date']);
1636 $this->assertEquals('2014-11-01', $result['start_date']);
1637 $this->assertEquals('2020-10-31', $result['end_date']);
1641 * Test that if membership start date is not set it defaults to correct end date for fixed single year memberships.
1643 public function testEmptyStartDateRolling() {
1644 unset($this->_params
['start_date'], $this->_params
['is_override']);
1645 $result = $this->callAPISuccess($this->_entity
, 'create', $this->_params
);
1646 $result = $this->callAPISuccess($this->_entity
, 'getsingle', ['id' => $result['id']]);
1647 $this->assertEquals('2009-01-21', $result['join_date']);
1648 $this->assertEquals('2009-01-21', $result['start_date']);
1649 $this->assertEquals('2009-12-21', $result['end_date']);
1653 * Test that if membership end date is not set it defaults to correct end date.
1656 public function testEmptyEndDateFixed() {
1657 unset($this->_params
['start_date'], $this->_params
['is_override'], $this->_params
['end_date']);
1658 $this->_params
['membership_type_id'] = $this->_membershipTypeID2
;
1659 $result = $this->callAPISuccess($this->_entity
, 'create', $this->_params
);
1660 $result = $this->callAPISuccess($this->_entity
, 'getsingle', ['id' => $result['id']]);
1661 $this->assertEquals('2009-01-21', $result['join_date']);
1662 $this->assertEquals('2008-03-01', $result['start_date']);
1663 $this->assertEquals('2010-02-28', $result['end_date']);
1667 * Test that if membership end date is not set it defaults to correct end date.
1670 public function testEmptyEndDateRolling() {
1671 unset($this->_params
['is_override'], $this->_params
['end_date']);
1672 $this->_params
['membership_type_id'] = $this->_membershipTypeID
;
1673 $result = $this->callAPISuccess($this->_entity
, 'create', $this->_params
);
1674 $result = $this->callAPISuccess($this->_entity
, 'getsingle', ['id' => $result['id']]);
1675 $this->assertEquals('2009-01-21', $result['join_date']);
1676 $this->assertEquals('2009-01-21', $result['start_date']);
1677 $this->assertEquals('2010-01-20', $result['end_date']);
1681 * Test that if dates are set they not over-ridden if id is passed in
1683 public function testMembershipDatesNotOverridden() {
1684 $result = $this->callAPISuccess($this->_entity
, 'create', $this->_params
);
1685 unset($this->_params
['end_date'], $this->_params
['start_date']);
1686 $this->_params
['id'] = $result['id'];
1687 $this->callAPISuccess($this->_entity
, 'create', $this->_params
);
1688 $result = $this->callAPISuccess($this->_entity
, 'getsingle', ['id' => $result['id']]);
1689 $this->assertEquals('2009-01-21', $result['join_date']);
1690 $this->assertEquals('2009-01-21', $result['start_date']);
1691 $this->assertEquals('2009-12-21', $result['end_date']);
1696 * Test that a contribution linked to multiple memberships results in all being updated.
1698 * @throws \CRM_Core_Exception
1700 public function testMultipleMembershipContribution() {
1701 $this->createMultipleMembershipOrder();
1702 $this->callAPISuccess('Payment', 'create', [
1703 'contribution_id' => $this->ids
['Contribution'][0],
1704 'payment_instrument_id' => 'Check',
1705 'total_amount' => 400,
1707 $memberships = $this->callAPISuccess('membership', 'get')['values'];
1708 $this->assertCount(2, $memberships);
1712 * Test that all membership types are returned when getoptions is called.
1714 * This test locks in current behaviour where types for all domains are returned. It should possibly be domain
1715 * specific but that should only be done in conjunction with adding a hook to allow that to be altered as the
1716 * multisite use case expects the master domain to be able to see all sites.
1720 public function testGetOptionsMembershipTypeID() {
1721 $options = $this->callAPISuccess('Membership', 'getoptions', ['field' => 'membership_type_id']);
1722 $this->assertEquals('Another one', array_pop($options['values']));
1723 $this->assertEquals('General', array_pop($options['values']));
1724 $this->assertEquals(NULL, array_pop($options['values']));