Remove legacy handling for 'fixing' line_item.entity_id
[civicrm-core.git] / tests / phpunit / api / v3 / MembershipTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
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 +--------------------------------------------------------------------+
10 */
11
12 /**
13 * Test APIv3 civicrm_membership functions
14 *
15 * @package CiviCRM_APIv3
16 * @subpackage API_Member
17 */
18
19 /**
20 * Class api_v3_MembershipTest
21 * @group headless
22 */
23 class api_v3_MembershipTest extends CiviUnitTestCase {
24
25 use CRMTraits_Financial_OrderTrait;
26
27 protected $_contactID;
28 protected $_membershipID;
29 protected $_membershipID2;
30 protected $_membershipID3;
31 protected $_membershipTypeID;
32 protected $_membershipTypeID2;
33 protected $_membershipStatusID;
34 protected $_entity;
35 protected $_params;
36
37 /**
38 * Set up for tests.
39 */
40 public function setUp() {
41 parent::setUp();
42 $this->_contactID = $this->individualCreate();
43 $this->_membershipTypeID = $this->membershipTypeCreate(['member_of_contact_id' => $this->_contactID]);
44 $this->_membershipTypeID2 = $this->membershipTypeCreate([
45 'period_type' => 'fixed',
46 // Ie. 1 March.
47 'fixed_period_start_day' => '301',
48 // Ie. 11 Nov.
49 'fixed_period_rollover_day' => '1111',
50 'name' => 'Another one',
51 ]);
52 $this->_membershipStatusID = $this->membershipStatusCreate('test status');
53
54 CRM_Member_PseudoConstant::membershipStatus(NULL, NULL, 'name', TRUE);
55 CRM_Core_PseudoConstant::activityType(TRUE, TRUE, TRUE, 'name');
56
57 $this->_entity = 'Membership';
58 $this->_params = [
59 'contact_id' => $this->_contactID,
60 'membership_type_id' => $this->_membershipTypeID,
61 'join_date' => '2009-01-21',
62 'start_date' => '2009-01-21',
63 'end_date' => '2009-12-21',
64 'source' => 'Payment',
65 'is_override' => 1,
66 'status_id' => $this->_membershipStatusID,
67 ];
68 }
69
70 /**
71 * Clean up after tests.
72 *
73 * @throws \Exception
74 */
75 public function tearDown() {
76 $this->quickCleanUpFinancialEntities();
77 $this->quickCleanup(['civicrm_uf_match'], TRUE);
78 $this->contactDelete($this->_contactID);
79 parent::tearDown();
80 }
81
82 /**
83 * Test membership deletion.
84 */
85 public function testMembershipDelete() {
86 $membershipID = $this->contactMembershipCreate($this->_params);
87 $this->assertDBRowExist('CRM_Member_DAO_Membership', $membershipID);
88 $params = [
89 'id' => $membershipID,
90 ];
91 $this->callAPIAndDocument('membership', 'delete', $params, __FUNCTION__, __FILE__);
92 $this->assertDBRowNotExist('CRM_Member_DAO_Membership', $membershipID);
93 }
94
95 public function testMembershipDeleteEmpty() {
96 $this->callAPIFailure('membership', 'delete', []);
97 }
98
99 public function testMembershipDeleteInvalidID() {
100 $this->callAPIFailure('membership', 'delete', ['id' => 'blah']);
101 }
102
103 /**
104 * Test membership deletion and with the preserve contribution param.
105 */
106 public function testMembershipDeletePreserveContribution() {
107 //DELETE
108 $membershipID = $this->contactMembershipCreate($this->_params);
109 //DELETE
110 $this->assertDBRowExist('CRM_Member_DAO_Membership', $membershipID);
111 $ContributionCreate = $this->callAPISuccess('Contribution', 'create', [
112 'sequential' => 1,
113 'financial_type_id' => "Member Dues",
114 'total_amount' => 100,
115 'contact_id' => $this->_params['contact_id'],
116 ]);
117 $this->callAPISuccess('MembershipPayment', 'create', [
118 'sequential' => 1,
119 'contribution_id' => $ContributionCreate['values'][0]['id'],
120 'membership_id' => $membershipID,
121 ]);
122 $memParams = [
123 'id' => $membershipID,
124 'preserve_contribution' => 1,
125 ];
126 $contribParams = [
127 'id' => $ContributionCreate['values'][0]['id'],
128 ];
129 $this->callAPIAndDocument('membership', 'delete', $memParams, __FUNCTION__, __FILE__);
130 $this->assertDBRowNotExist('CRM_Member_DAO_Membership', $membershipID);
131 $this->assertDBRowExist('CRM_Contribute_DAO_Contribution', $ContributionCreate['values'][0]['id']);
132 $this->callAPISuccess('Contribution', 'delete', $contribParams);
133 $this->assertDBRowNotExist('CRM_Contribute_DAO_Contribution', $ContributionCreate['values'][0]['id']);
134 }
135
136 /**
137 * Test Activity creation on cancellation of membership contribution.
138 */
139 public function testActivityForCancelledContribution() {
140 $contactId = $this->createLoggedInUser();
141 $membershipID = $this->contactMembershipCreate($this->_params);
142
143 $ContributionCreate = $this->callAPISuccess('Contribution', 'create', [
144 'financial_type_id' => 'Member Dues',
145 'total_amount' => 100,
146 'contact_id' => $this->_params['contact_id'],
147 ]);
148 $this->callAPISuccess('MembershipPayment', 'create', [
149 'sequential' => 1,
150 'contribution_id' => $ContributionCreate['id'],
151 'membership_id' => $membershipID,
152 ]);
153
154 $form = new CRM_Contribute_Form_Contribution();
155 $form->_id = $ContributionCreate['id'];
156 $form->testSubmit([
157 'total_amount' => 100,
158 'financial_type_id' => 1,
159 'contact_id' => $contactId,
160 'payment_instrument_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Check'),
161 'contribution_status_id' => 3,
162 ],
163 CRM_Core_Action::UPDATE);
164
165 $this->callAPISuccessGetSingle('Activity', [
166 'activity_type_id' => 'Membership Signup',
167 'source_record_id' => $membershipID,
168 'subject' => 'General - Payment - Status: test status',
169 ]);
170 $this->callAPISuccessGetSingle('Activity', [
171 'activity_type_id' => 'Change Membership Status',
172 'source_record_id' => $membershipID,
173 ]);
174 }
175
176 /**
177 * Test membership get.
178 */
179 public function testContactMembershipsGet() {
180 $this->_membershipID = $this->contactMembershipCreate($this->_params);
181 $this->callAPISuccess('membership', 'get', []);
182 $this->callAPISuccess('Membership', 'Delete', ['id' => $this->_membershipID]);
183 }
184
185 /**
186 * Test civicrm_membership_get with params not array.
187 *
188 * Gets treated as contact_id, memberships expected.
189 */
190 public function testGetWithParamsContactId() {
191 $this->_membershipID = $this->contactMembershipCreate($this->_params);
192 $params = [
193 'contact_id' => $this->_contactID,
194 ];
195 $membership = $this->callAPISuccess('membership', 'get', $params);
196
197 $result = $membership['values'][$this->_membershipID];
198 $this->callAPISuccess('Membership', 'Delete', [
199 'id' => $this->_membershipID,
200 ]);
201 $this->assertEquals($result['contact_id'], $this->_contactID);
202 $this->assertEquals($result['membership_type_id'], $this->_membershipTypeID);
203 $this->assertEquals($result['status_id'], $this->_membershipStatusID);
204 $this->assertEquals($result['join_date'], '2009-01-21');
205 $this->assertEquals($result['start_date'], '2009-01-21');
206 $this->assertEquals($result['end_date'], '2009-12-21');
207 $this->assertEquals($result['source'], 'Payment');
208 $this->assertEquals($result['is_override'], 1);
209 }
210
211 /**
212 * Test civicrm_membership_get with params not array.
213 *
214 * Gets treated as contact_id, memberships expected.
215 */
216 public function testGetInSyntax() {
217 $this->_membershipID = $this->contactMembershipCreate($this->_params);
218 $this->_membershipID2 = $this->contactMembershipCreate($this->_params);
219 $this->_membershipID3 = $this->contactMembershipCreate($this->_params);
220 $params = [
221 'id' => ['IN' => [$this->_membershipID, $this->_membershipID3]],
222 ];
223 $membership = $this->callAPISuccess('membership', 'get', $params);
224 $this->assertEquals(2, $membership['count']);
225 $this->assertEquals([$this->_membershipID, $this->_membershipID3], array_keys($membership['values']));
226 $params = [
227 'id' => ['NOT IN' => [$this->_membershipID, $this->_membershipID3]],
228 ];
229 $membership = $this->callAPISuccess('membership', 'get', $params);
230 $this->assertEquals(1, $membership['count']);
231 $this->assertEquals([$this->_membershipID2], array_keys($membership['values']));
232 }
233
234 /**
235 * Test civicrm_membership_get with params not array.
236 * Gets treated as contact_id, memberships expected.
237 */
238 public function testGetInSyntaxOnContactID() {
239 $this->_membershipID = $this->contactMembershipCreate($this->_params);
240 $contact2 = $this->individualCreate();
241 $contact3 = $this->individualCreate(['first_name' => 'Scout', 'last_name' => 'Canine']);
242 $this->_membershipID2 = $this->contactMembershipCreate(array_merge($this->_params, ['contact_id' => $contact2]));
243 $this->_membershipID3 = $this->contactMembershipCreate(array_merge($this->_params, ['contact_id' => $contact3]));
244 $params = [
245 'contact_id' => ['IN' => [$this->_contactID, $contact3]],
246 ];
247 $membership = $this->callAPISuccess('membership', 'get', $params);
248 $this->assertEquals(2, $membership['count']);
249 $this->assertEquals([$this->_membershipID, $this->_membershipID3], array_keys($membership['values']));
250 $params = [
251 'contact_id' => ['NOT IN' => [$this->_contactID, $contact3]],
252 ];
253 $membership = $this->callAPISuccess('membership', 'get', $params);
254 $this->assertEquals(1, $membership['count']);
255 $this->assertEquals([$this->_membershipID2], array_keys($membership['values']));
256 }
257
258 /**
259 * Test civicrm_membership_get with params not array.
260 *
261 * Gets treated as contact_id, memberships expected.
262 */
263 public function testGetWithParamsMemberShipTypeId() {
264 $this->callAPISuccess($this->_entity, 'create', $this->_params);
265 $params = [
266 'membership_type_id' => $this->_membershipTypeID,
267 ];
268 $membership = $this->callAPISuccess('membership', 'get', $params);
269 $this->callAPISuccess('Membership', 'Delete', [
270 'id' => $membership['id'],
271 ]);
272 $result = $membership['values'][$membership['id']];
273 $this->assertEquals($result['contact_id'], $this->_contactID);
274 $this->assertEquals($result['membership_type_id'], $this->_membershipTypeID);
275 $this->assertEquals($result['status_id'], $this->_membershipStatusID);
276 $this->assertEquals($result['join_date'], '2009-01-21');
277 $this->assertEquals($result['start_date'], '2009-01-21');
278 $this->assertEquals($result['end_date'], '2009-12-21');
279 $this->assertEquals($result['source'], 'Payment');
280 $this->assertEquals($result['is_override'], 1);
281 $this->assertEquals($result['id'], $membership['id']);
282 }
283
284 /**
285 * Test civicrm_membership_get with params not array.
286 * Gets treated as contact_id, memberships expected.
287 */
288 public function testGetWithParamsMemberShipTypeIdContactID() {
289 $params = $this->_params;
290 $this->callAPISuccess($this->_entity, 'create', $params);
291 $params['membership_type_id'] = $this->_membershipTypeID2;
292 $this->callAPISuccess($this->_entity, 'create', $params);
293 $this->callAPISuccessGetCount('membership', ['contact_id' => $this->_contactID], 2);
294 $params = [
295 'membership_type_id' => $this->_membershipTypeID,
296 'contact_id' => $this->_contactID,
297 ];
298 $result = $this->callAPISuccess('membership', 'getsingle', $params);
299 $this->assertEquals($result['contact_id'], $this->_contactID);
300 $this->assertEquals($result['membership_type_id'], $this->_membershipTypeID);
301
302 $params = [
303 'membership_type_id' => $this->_membershipTypeID2,
304 'contact_id' => $this->_contactID,
305 ];
306 $result = $this->callAPISuccess('membership', 'getsingle', $params);
307 $this->assertEquals($result['contact_id'], $this->_contactID);
308 $this->assertEquals($result['membership_type_id'], $this->_membershipTypeID2);
309 }
310
311 /**
312 * Check with complete array + custom field.
313 *
314 * Note that the test is written on purpose without any
315 * variables specific to participant so it can be replicated into other entities
316 * and / or moved to the automated test suite
317 */
318 public function testGetWithParamsMemberShipIdAndCustom() {
319 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
320
321 $params = $this->_params;
322 $params['custom_' . $ids['custom_field_id']] = "custom string";
323
324 $result = $this->callAPISuccess($this->_entity, 'create', $params);
325
326 $getParams = ['membership_type_id' => $params['membership_type_id']];
327 $check = $this->callAPIAndDocument($this->_entity, 'get', $getParams, __FUNCTION__, __FILE__);
328 $this->assertEquals("custom string", $check['values'][$result['id']]['custom_' . $ids['custom_field_id']], ' in line ' . __LINE__);
329
330 $this->callAPISuccess('Membership', 'Delete', [
331 'id' => $result['id'],
332 ]);
333 }
334
335 /**
336 * Test civicrm_membership_get with proper params.
337 * Memberships expected.
338 */
339 public function testGet() {
340 $membershipID = $this->contactMembershipCreate($this->_params);
341 $params = [
342 'contact_id' => $this->_contactID,
343 ];
344
345 $membership = $this->callAPISuccess('membership', 'get', $params);
346 $result = $membership['values'][$membershipID];
347 $this->callAPISuccess('Membership', 'Delete', [
348 'id' => $membership['id'],
349 ]);
350 $this->assertEquals($result['join_date'], '2009-01-21');
351 $this->assertEquals($result['contact_id'], $this->_contactID);
352 $this->assertEquals($result['membership_type_id'], $this->_membershipTypeID);
353 $this->assertEquals($result['status_id'], $this->_membershipStatusID);
354
355 $this->assertEquals($result['start_date'], '2009-01-21');
356 $this->assertEquals($result['end_date'], '2009-12-21');
357 $this->assertEquals($result['source'], 'Payment');
358 $this->assertEquals($result['is_override'], 1);
359 }
360
361 /**
362 * Test civicrm_membership_get with proper params.
363 * Memberships expected.
364 */
365 public function testGetWithId() {
366 $membershipID = $this->contactMembershipCreate($this->_params);
367 $params = [
368 'contact_id' => $this->_contactID,
369 'id' => $this->_membershipID,
370 'return' => 'id',
371 ];
372 $result = $this->callAPISuccess('membership', 'get', $params);
373 $this->assertEquals($membershipID, $result['id']);
374 $params = [
375 'contact_id' => $this->_contactID,
376 'membership_id' => $this->_membershipID,
377 'return' => 'membership_id',
378 ];
379 $result = $this->callAPISuccess('membership', 'get', $params);
380 $this->assertEquals($membershipID, $result['id']);
381 }
382
383 /**
384 * Test civicrm_membership_get for only active.
385 * Memberships expected.
386 */
387 public function testGetOnlyActive() {
388 $description = "Demonstrates use of 'filter' active_only' param.";
389 $this->_membershipID = $this->contactMembershipCreate($this->_params);
390 $params = [
391 'contact_id' => $this->_contactID,
392 'active_only' => 1,
393 ];
394
395 $membership = $this->callAPISuccess('membership', 'get', $params);
396 $this->assertEquals($membership['values'][$this->_membershipID]['status_id'], $this->_membershipStatusID);
397 $this->assertEquals($membership['values'][$this->_membershipID]['contact_id'], $this->_contactID);
398 $params = [
399 'contact_id' => $this->_contactID,
400 'filters' => [
401 'is_current' => 1,
402 ],
403 ];
404
405 $membership = $this->callAPIAndDocument('membership', 'get', $params, __FUNCTION__, __FILE__, $description, 'FilterIsCurrent');
406 $this->assertEquals($membership['values'][$this->_membershipID]['status_id'], $this->_membershipStatusID);
407 $this->assertEquals($membership['values'][$this->_membershipID]['contact_id'], $this->_contactID);
408
409 $this->callAPISuccess('Membership', 'Delete', ['id' => $this->_membershipID]);
410 }
411
412 /**
413 * Test civicrm_membership_get for non exist contact.
414 * empty Memberships.
415 */
416 public function testGetNoContactExists() {
417 $params = [
418 'contact_id' => 55555,
419 ];
420
421 $membership = $this->callAPISuccess('membership', 'get', $params);
422 $this->assertEquals($membership['count'], 0);
423 }
424
425 /**
426 * Test civicrm_membership_get with relationship.
427 * get Memberships.
428 *
429 * @throws \CRM_Core_Exception
430 */
431 public function testGetWithRelationship() {
432 $membershipOrgId = $this->organizationCreate(NULL);
433 $memberContactId = $this->individualCreate();
434
435 $relTypeParams = [
436 'name_a_b' => 'Relation 1',
437 'name_b_a' => 'Relation 2',
438 'description' => 'Testing relationship type',
439 'contact_type_a' => 'Organization',
440 'contact_type_b' => 'Individual',
441 'is_reserved' => 1,
442 'is_active' => 1,
443 ];
444 $relTypeID = $this->relationshipTypeCreate($relTypeParams);
445
446 $params = [
447 'name' => 'test General',
448 'duration_unit' => 'year',
449 'duration_interval' => 1,
450 'period_type' => 'rolling',
451 'member_of_contact_id' => $membershipOrgId,
452 'domain_id' => 1,
453 'financial_type_id' => 1,
454 'relationship_type_id' => $relTypeID,
455 'relationship_direction' => 'b_a',
456 'is_active' => 1,
457 ];
458 $memType = $this->callAPISuccess('membership_type', 'create', $params);
459
460 $params = [
461 'contact_id' => $memberContactId,
462 'membership_type_id' => $memType['id'],
463 'join_date' => '2009-01-21',
464 'start_date' => '2009-01-21',
465 'end_date' => '2009-12-21',
466 'source' => 'Payment',
467 'is_override' => 1,
468 'status_id' => $this->_membershipStatusID,
469 ];
470 $membershipID = $this->contactMembershipCreate($params);
471
472 $params = [
473 'contact_id' => $memberContactId,
474 'membership_type_id' => $memType['id'],
475 ];
476
477 $result = $this->callAPISuccess('membership', 'get', $params);
478
479 $membership = $result['values'][$membershipID];
480 $this->assertEquals($this->_membershipStatusID, $membership['status_id']);
481 $this->callAPISuccess('Membership', 'Delete', [
482 'id' => $membership['id'],
483 ]);
484 $this->membershipTypeDelete(['id' => $memType['id']]);
485 $this->relationshipTypeDelete($relTypeID);
486 $this->contactDelete($membershipOrgId);
487 $this->contactDelete($memberContactId);
488 }
489
490 /**
491 * Test civicrm_membership_create with relationships.
492 * create/get Memberships.
493 *
494 * Test suite for CRM-14758: API ( contact, create ) does not always create related membership
495 * and max_related property for Membership_Type and Membership entities
496 *
497 * @throws \CRM_Core_Exception
498 * @throws \CiviCRM_API3_Exception
499 */
500 public function testCreateWithRelationship() {
501 // Create membership type: inherited through employment, max_related = 2
502 $params = [
503 'name_a_b' => 'Employee of',
504 ];
505 $result = $this->callAPISuccess('relationship_type', 'get', $params);
506 $relationshipTypeId = $result['id'];
507 $membershipOrgId = $this->organizationCreate();
508 $params = [
509 'name' => 'Corporate Membership',
510 'duration_unit' => 'year',
511 'duration_interval' => 1,
512 'period_type' => 'rolling',
513 'member_of_contact_id' => $membershipOrgId,
514 'domain_id' => 1,
515 'financial_type_id' => 1,
516 'relationship_type_id' => $relationshipTypeId,
517 'relationship_direction' => 'b_a',
518 'max_related' => 2,
519 'is_active' => 1,
520 ];
521 $result = $this->callAPISuccess('membership_type', 'create', $params);
522 $membershipTypeId = $result['id'];
523
524 // Create employer and first employee
525 $employerId[0] = $this->organizationCreate([], 1);
526 $memberContactId[0] = $this->individualCreate(['employer_id' => $employerId[0]], 0);
527
528 // Create organization's membership
529 $params = [
530 'contact_id' => $employerId[0],
531 'membership_type_id' => $membershipTypeId,
532 'source' => 'Test suite',
533 'start_date' => date('Y-m-d'),
534 'end_date' => '+1 year',
535 ];
536 $OrganizationMembershipID = $this->contactMembershipCreate($params);
537
538 // Check that the employee inherited the membership
539 $params = [
540 'contact_id' => $memberContactId[0],
541 'membership_type_id' => $membershipTypeId,
542 ];
543
544 $result = $this->callAPISuccess('membership', 'get', $params);
545
546 $this->assertEquals(1, $result['count']);
547 $result = $result['values'][$result['id']];
548 $this->assertEquals($OrganizationMembershipID, $result['owner_membership_id']);
549
550 // Create second employee
551 $memberContactId[1] = $this->individualCreate(['employer_id' => $employerId[0]], 1);
552
553 // Check that the employee inherited the membership
554 $params = [
555 'contact_id' => $memberContactId[1],
556 'membership_type_id' => $membershipTypeId,
557 ];
558 $result = $this->callAPISuccess('membership', 'get', $params);
559 // If it fails here CRM-14758 is not fixed
560 $this->assertEquals(1, $result['count']);
561 $result = $result['values'][$result['id']];
562 $this->assertEquals($OrganizationMembershipID, $result['owner_membership_id']);
563
564 // Create third employee
565 $memberContactId[2] = $this->individualCreate(['employer_id' => $employerId[0]], 2);
566
567 // Check that employee does NOT inherit the membership (max_related = 2)
568 $params = [
569 'contact_id' => $memberContactId[2],
570 'membership_type_id' => $membershipTypeId,
571 ];
572 $result = $this->callAPISuccess('membership', 'get', $params);
573 $this->assertEquals(0, $result['count']);
574
575 // Increase max_related for the employer's membership
576 $params = [
577 'id' => $OrganizationMembershipID,
578 'max_related' => 3,
579 ];
580 $this->callAPISuccess('Membership', 'create', $params);
581
582 // Check that the employee inherited the membership
583 $params = [
584 'contact_id' => $memberContactId[2],
585 'membership_type_id' => $membershipTypeId,
586 ];
587 $result = $this->callAPISuccess('membership', 'get', $params);
588 $this->assertEquals(1, $result['count']);
589 $result = $result['values'][$result['id']];
590 $this->assertEquals($OrganizationMembershipID, $result['owner_membership_id']);
591
592 // First employee moves to a new job
593 $employerId[1] = $this->organizationCreate([], 2);
594 $params = [
595 'id' => $memberContactId[0],
596 'employer_id' => $employerId[1],
597 ];
598 $this->callAPISuccess('contact', 'create', $params);
599
600 // Check that employee does NO LONGER inherit the membership
601 $params = [
602 'contact_id' => $memberContactId[0],
603 'membership_type_id' => $membershipTypeId,
604 ];
605 $result = $this->callAPISuccess('membership', 'get', $params);
606 $this->assertEquals(0, $result['count']);
607
608 //Create pay_later membership for organization.
609 $employerId[2] = $this->organizationCreate([], 1);
610 $params = [
611 'contact_id' => $employerId[2],
612 'membership_type_id' => $membershipTypeId,
613 'source' => 'Test pay later suite',
614 'is_pay_later' => 1,
615 'status_id' => 5,
616 ];
617 $organizationMembershipID = $this->callAPISuccess('Membership', 'create', $params)['id'];
618
619 $memberContactId[3] = $this->individualCreate(['employer_id' => $employerId[2]], 0);
620 // Check that the employee inherited the membership
621 $params = [
622 'contact_id' => $memberContactId[3],
623 'membership_type_id' => $membershipTypeId,
624 ];
625 $result = $this->callAPISuccessGetSingle('membership', $params);
626 $this->assertEquals($organizationMembershipID, $result['owner_membership_id']);
627
628 // Set up params for enable/disable checks
629 $relationship1 = $this->callAPISuccess('relationship', 'get', ['contact_id_a' => $memberContactId[1]]);
630 $params = [
631 'contact_id' => $memberContactId[1],
632 'membership_type_id' => $membershipTypeId,
633 ];
634
635 // Deactivate relationship using create and assert membership is not inherited
636 $this->callAPISuccess('relationship', 'create', ['id' => $relationship1['id'], 'is_active' => 0]);
637 $result = $this->callAPISuccess('membership', 'get', $params);
638 $this->assertEquals(0, $result['count']);
639
640 // Re-enable relationship using create and assert membership is inherited
641 $this->callAPISuccess('relationship', 'create', ['id' => $relationship1['id'], 'is_active' => 1]);
642 $result = $this->callAPISuccess('membership', 'get', $params);
643 $this->assertEquals(1, $result['count']);
644
645 // Deactivate relationship using setvalue and assert membership is not inherited
646 $this->callAPISuccess('relationship', 'setvalue', ['id' => $relationship1['id'], 'field' => 'is_active', 'value' => 0]);
647 $result = $this->callAPISuccess('membership', 'get', $params);
648 $this->assertEquals(0, $result['count']);
649
650 // Re-enable relationship using setvalue and assert membership is inherited
651 $this->callAPISuccess('relationship', 'setvalue', ['id' => $relationship1['id'], 'field' => 'is_active', 'value' => 1]);
652 $result = $this->callAPISuccess('membership', 'get', $params);
653 $this->assertEquals(1, $result['count']);
654
655 // Delete relationship and assert membership is not inherited
656 $this->callAPISuccess('relationship', 'delete', ['id' => $relationship1['id']]);
657 $result = $this->callAPISuccess('membership', 'get', $params);
658 $this->assertEquals(0, $result['count']);
659
660 // Tear down - reverse of creation to be safe
661 $this->contactDelete($memberContactId[2]);
662 $this->contactDelete($memberContactId[1]);
663 $this->contactDelete($memberContactId[0]);
664 $this->contactDelete($employerId[1]);
665 $this->contactDelete($employerId[0]);
666 $this->membershipTypeDelete(['id' => $membershipTypeId]);
667 $this->contactDelete($membershipOrgId);
668 }
669
670 /**
671 * We are checking for no e-notices + only id & end_date returned
672 *
673 * @throws \CRM_Core_Exception
674 */
675 public function testMembershipGetWithReturn() {
676 $this->contactMembershipCreate($this->_params);
677 $result = $this->callAPISuccess('membership', 'get', ['return' => 'end_date']);
678 foreach ($result['values'] as $membership) {
679 $this->assertEquals(['id', 'end_date'], array_keys($membership));
680 }
681 }
682
683 ///////////////// civicrm_membership_create methods
684
685 /**
686 * Test civicrm_contact_memberships_create with empty params.
687 * Error expected.
688 */
689 public function testCreateWithEmptyParams() {
690 $params = [];
691 $this->callAPIFailure('membership', 'create', $params);
692 }
693
694 /**
695 * If is_overide is passed in status must also be passed in.
696 */
697 public function testCreateOverrideNoStatus() {
698 $params = $this->_params;
699 unset($params['status_id']);
700 $this->callAPIFailure('membership', 'create', $params);
701 }
702
703 public function testMembershipCreateMissingRequired() {
704 $params = [
705 'membership_type_id' => '1',
706 'join_date' => '2006-01-21',
707 'start_date' => '2006-01-21',
708 'end_date' => '2006-12-21',
709 'source' => 'Payment',
710 'status_id' => '2',
711 ];
712
713 $this->callAPIFailure('membership', 'create', $params);
714 }
715
716 public function testMembershipCreate() {
717 $params = [
718 'contact_id' => $this->_contactID,
719 'membership_type_id' => $this->_membershipTypeID,
720 'join_date' => '2006-01-21',
721 'start_date' => '2006-01-21',
722 'end_date' => '2006-12-21',
723 'source' => 'Payment',
724 'is_override' => 1,
725 'status_id' => $this->_membershipStatusID,
726 ];
727
728 $result = $this->callAPIAndDocument('membership', 'create', $params, __FUNCTION__, __FILE__);
729 $this->getAndCheck($params, $result['id'], $this->_entity);
730 $this->assertNotNull($result['id']);
731 $this->assertEquals($this->_contactID, $result['values'][$result['id']]['contact_id'], " in line " . __LINE__);
732 $this->assertEquals($result['id'], $result['values'][$result['id']]['id'], " in line " . __LINE__);
733 }
734
735 /**
736 * Check for useful message if contact doesn't exist
737 */
738 public function testMembershipCreateWithInvalidContact() {
739 $params = [
740 'contact_id' => 999,
741 'membership_type_id' => $this->_membershipTypeID,
742 'join_date' => '2006-01-21',
743 'start_date' => '2006-01-21',
744 'end_date' => '2006-12-21',
745 'source' => 'Payment',
746 'is_override' => 1,
747 'status_id' => $this->_membershipStatusID,
748 ];
749
750 $this->callAPIFailure('membership', 'create', $params,
751 'contact_id is not valid : 999'
752 );
753 }
754
755 public function testMembershipCreateWithInvalidStatus() {
756 $params = $this->_params;
757 $params['status_id'] = 999;
758 $this->callAPIFailure('membership', 'create', $params,
759 "'999' is not a valid option for field status_id"
760 );
761 }
762
763 public function testMembershipCreateWithInvalidType() {
764 $params = $this->_params;
765 $params['membership_type_id'] = 999;
766
767 $this->callAPIFailure('membership', 'create', $params,
768 "'999' is not a valid option for field membership_type_id"
769 );
770 }
771
772 /**
773 * Check with complete array + custom field
774 * Note that the test is written on purpose without any
775 * variables specific to participant so it can be replicated into other entities
776 * and / or moved to the automated test suite
777 */
778 public function testCreateWithCustom() {
779 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
780
781 $params = $this->_params;
782 $params['custom_' . $ids['custom_field_id']] = "custom string";
783
784 $result = $this->callAPIAndDocument($this->_entity, 'create', $params, __FUNCTION__, __FILE__, NULL, 'CreateWithCustomData');
785 $check = $this->callAPISuccess($this->_entity, 'get', [
786 'id' => $result['id'],
787 'contact_id' => $this->_contactID,
788 ]);
789 $this->assertEquals("custom string", $check['values'][$result['id']]['custom_' . $ids['custom_field_id']], ' in line ' . __LINE__);
790 }
791
792 /**
793 * Search on custom field value.
794 */
795 public function testSearchWithCustomDataCRM16036() {
796 // Create a custom field on membership
797 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
798
799 // Create a new membership, but don't assign anything to the custom field.
800 $params = $this->_params;
801 $result = $this->callAPIAndDocument(
802 $this->_entity,
803 'create',
804 $params,
805 __FUNCTION__,
806 __FILE__,
807 NULL,
808 'SearchWithCustomData');
809
810 // search memberships with CRM-16036 as custom field value.
811 // Since we did not touch the custom field of any membership,
812 // this should not return any results.
813 $check = $this->callAPISuccess($this->_entity, 'get', [
814 'custom_' . $ids['custom_field_id'] => "CRM-16036",
815 ]);
816
817 // Cleanup.
818 $this->callAPISuccess($this->_entity, 'delete', [
819 'id' => $result['id'],
820 ]);
821
822 // Assert.
823 $this->assertEquals(0, $check['count']);
824 }
825
826 /**
827 * Test civicrm_contact_memberships_create with membership id (edit
828 * membership).
829 * success expected.
830 */
831 public function testMembershipCreateWithId() {
832 $membershipID = $this->contactMembershipCreate($this->_params);
833 $params = [
834 'id' => $membershipID,
835 'contact_id' => $this->_contactID,
836 'membership_type_id' => $this->_membershipTypeID,
837 'join_date' => '2006-01-21',
838 'start_date' => '2006-01-21',
839 'end_date' => '2006-12-21',
840 'source' => 'Payment',
841 'is_override' => 1,
842 'status_id' => $this->_membershipStatusID,
843 ];
844
845 $result = $this->callAPISuccess('membership', 'create', $params);
846
847 //Update Status and check activities created.
848 $updateStatus = [
849 'id' => $result['id'],
850 'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Member_BAO_Membership', 'status_id', 'Cancelled'),
851 ];
852 $this->callAPISuccess('Membership', 'create', $updateStatus);
853 $activities = CRM_Activity_BAO_Activity::getContactActivity($this->_contactID);
854 $this->assertEquals(2, count($activities));
855 $activityNames = array_flip(CRM_Utils_Array::collect('activity_name', $activities));
856 $this->assertArrayHasKey('Membership Signup', $activityNames);
857 $this->assertArrayHasKey('Change Membership Status', $activityNames);
858
859 $this->callAPISuccess('Membership', 'Delete', [
860 'id' => $result['id'],
861 ]);
862 $this->assertEquals($result['id'], $membershipID, "in line " . __LINE__);
863 }
864
865 /**
866 * Test civicrm_contact_memberships_create with membership id (edit
867 * membership).
868 * success expected.
869 */
870 public function testMembershipCreateUpdateWithIdNoContact() {
871 $membershipID = $this->contactMembershipCreate($this->_params);
872 $params = [
873 'id' => $membershipID,
874 'membership_type_id' => $this->_membershipTypeID,
875 'contact_id' => $this->_contactID,
876 'join_date' => '2006-01-21',
877 'start_date' => '2006-01-21',
878 'end_date' => '2006-12-21',
879 'source' => 'Payment',
880 'is_override' => 1,
881 'status_id' => $this->_membershipStatusID,
882 ];
883
884 $result = $this->callAPISuccess('membership', 'create', $params);
885 $this->callAPISuccess('Membership', 'Delete', [
886 'id' => $result['id'],
887 ]);
888
889 $this->assertEquals($result['id'], $membershipID, "in line " . __LINE__);
890 }
891
892 /**
893 * Test civicrm_contact_memberships_create with membership id (edit
894 * membership).
895 * success expected.
896 */
897 public function testMembershipCreateUpdateWithIdNoDates() {
898 $membershipID = $this->contactMembershipCreate($this->_params);
899 $params = [
900 'id' => $membershipID,
901 'contact_id' => $this->_contactID,
902 'membership_type_id' => $this->_membershipTypeID,
903 'source' => 'Payment',
904 'is_override' => 1,
905 'status_id' => $this->_membershipStatusID,
906 ];
907
908 $result = $this->callAPISuccess('membership', 'create', $params);
909 $this->callAPISuccess('Membership', 'Delete', [
910 'id' => $result['id'],
911 ]);
912 $this->assertEquals($result['id'], $membershipID, "in line " . __LINE__);
913 }
914
915 /**
916 * Test civicrm_contact_memberships_create with membership id (edit
917 * membership).
918 * success expected.
919 */
920 public function testMembershipCreateUpdateWithIdNoDatesNoType() {
921 $membershipID = $this->contactMembershipCreate($this->_params);
922 $params = [
923 'id' => $membershipID,
924 'source' => 'not much here',
925 'contact_id' => $this->_contactID,
926 'is_override' => 1,
927 'status_id' => $this->_membershipStatusID,
928 ];
929
930 $result = $this->callAPISuccess('membership', 'create', $params);
931 $this->callAPISuccess('Membership', 'Delete', [
932 'id' => $result['id'],
933 ]);
934 $this->assertEquals($result['id'], $membershipID, "in line " . __LINE__);
935 }
936
937 /**
938 * Test civicrm_contact_memberships_create with membership id (edit
939 * membership).
940 * success expected.
941 */
942 public function testMembershipCreateUpdateWithIDAndSource() {
943 $membershipID = $this->contactMembershipCreate($this->_params);
944 $params = [
945 'id' => $membershipID,
946 'source' => 'changed',
947 'contact_id' => $this->_contactID,
948 'status_id' => $this->_membershipStatusID,
949 'membership_type_id' => $this->_membershipTypeID,
950 'skipStatusCal' => 1,
951 ];
952 $result = $this->callAPISuccess('membership', 'create', $params);
953 $this->assertEquals($result['id'], $membershipID, "in line " . __LINE__);
954 $this->callAPISuccess('Membership', 'Delete', [
955 'id' => $result['id'],
956 ]);
957 }
958
959 /**
960 * Change custom field using update.
961 */
962 public function testUpdateWithCustom() {
963 $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, __FILE__);
964
965 $params = $this->_params;
966 $params['custom_' . $ids['custom_field_id']] = "custom string";
967 $result = $this->callAPIAndDocument($this->_entity, 'create', $params, __FUNCTION__, __FILE__, NULL, 'UpdateCustomData');
968 $result = $this->callAPISuccess($this->_entity, 'create', [
969 'id' => $result['id'],
970 'custom_' . $ids['custom_field_id'] => "new custom",
971 ]);
972 $check = $this->callAPISuccess($this->_entity, 'get', [
973 'id' => $result['id'],
974 'contact_id' => $this->_contactID,
975 ]);
976
977 $this->assertEquals("new custom", $check['values'][$result['id']]['custom_' . $ids['custom_field_id']], ' in line ' . __LINE__);
978 $this->callAPISuccess('Membership', 'Delete', [
979 'id' => $check['id'],
980 ]);
981
982 $this->customFieldDelete($ids['custom_field_id']);
983 $this->customGroupDelete($ids['custom_group_id']);
984 }
985
986 /**
987 * per CRM-15746 check that the id can be altered in an update hook
988 */
989 public function testMembershipUpdateCreateHookCRM15746() {
990 $this->hookClass->setHook('civicrm_pre', [$this, 'hook_civicrm_pre_update_create_membership']);
991 $result = $this->callAPISuccess('membership', 'create', $this->_params);
992 $this->callAPISuccess('membership', 'create', ['id' => $result['id'], 'end_date' => '1 year ago']);
993 $this->callAPISuccessGetCount('membership', [], 2);
994 $this->hookClass->reset();
995 $this->callAPISuccess('membership', 'create', ['id' => $result['id'], 'end_date' => '1 year ago']);
996 $this->callAPISuccessGetCount('membership', [], 2);
997 }
998
999 /**
1000 * Custom hook for update membership.
1001 *
1002 * @param string $op
1003 * @param object $objectName
1004 * @param int $id
1005 * @param array $params
1006 *
1007 * @throws \Exception
1008 */
1009 public function hook_civicrm_pre_update_create_membership($op, $objectName, $id, &$params) {
1010 if ($objectName === 'Membership' && $op === 'edit') {
1011 $existingMembership = $this->callAPISuccessGetSingle('membership', ['id' => $params['id']]);
1012 unset($params['id'], $params['membership_id']);
1013 $params['join_date'] = $params['membership_start_date'] = $params['start_date'] = date('Ymd000000', strtotime($existingMembership['start_date']));
1014 $params = array_merge($existingMembership, $params);
1015 $params['id'] = NULL;
1016 }
1017 }
1018
1019 /**
1020 * Test civicrm_contact_memberships_create Invalid membership data.
1021 * Error expected.
1022 */
1023 public function testMembershipCreateInvalidMemData() {
1024 //membership_contact_id as string
1025 $params = [
1026 'membership_contact_id' => 'Invalid',
1027 'membership_type_id' => $this->_membershipTypeID,
1028 'join_date' => '2011-01-21',
1029 'start_date' => '2010-01-21',
1030 'end_date' => '2008-12-21',
1031 'source' => 'Payment',
1032 'is_override' => 1,
1033 'status_id' => $this->_membershipStatusID,
1034 ];
1035
1036 $this->callAPIFailure('membership', 'create', $params);
1037
1038 //membership_contact_id which is no in contact table
1039 $params['membership_contact_id'] = 999;
1040 $this->callAPIFailure('membership', 'create', $params);
1041
1042 //invalid join date
1043 unset($params['membership_contact_id']);
1044 $params['join_date'] = "invalid";
1045 $this->callAPIFailure('Membership', 'Create', $params);
1046 }
1047
1048 /**
1049 * Test civicrm_contact_memberships_create with membership_contact_id
1050 * membership).
1051 * Success expected.
1052 */
1053 public function testMembershipCreateWithMemContact() {
1054 $params = [
1055 'membership_contact_id' => $this->_contactID,
1056 'membership_type_id' => $this->_membershipTypeID,
1057 'join_date' => '2011-01-21',
1058 'start_date' => '2010-01-21',
1059 'end_date' => '2008-12-21',
1060 'source' => 'Payment',
1061 'is_override' => 1,
1062 'status_id' => $this->_membershipStatusID,
1063 ];
1064
1065 $result = $this->callAPISuccess('membership', 'create', $params);
1066
1067 $this->callAPISuccess('Membership', 'Delete', [
1068 'id' => $result['id'],
1069 ]);
1070 }
1071
1072 /**
1073 * Test civicrm_contact_memberships_create with membership_contact_id
1074 * membership).
1075 * Success expected.
1076 */
1077 public function testMembershipCreateValidMembershipTypeString() {
1078 $params = [
1079 'membership_contact_id' => $this->_contactID,
1080 'membership_type_id' => 'General',
1081 'join_date' => '2011-01-21',
1082 'start_date' => '2010-01-21',
1083 'end_date' => '2008-12-21',
1084 'source' => 'Payment',
1085 'is_override' => 1,
1086 'status_id' => $this->_membershipStatusID,
1087 ];
1088
1089 $result = $this->callAPISuccess('membership', 'create', $params);
1090 $this->assertEquals($this->_membershipTypeID, $result['values'][$result['id']]['membership_type_id']);
1091 $this->callAPISuccess('Membership', 'Delete', [
1092 'id' => $result['id'],
1093 ]);
1094 }
1095
1096 /**
1097 * Test civicrm_contact_memberships_create with membership_contact_id
1098 * membership).
1099 * Success expected.
1100 */
1101 public function testMembershipCreateInValidMembershipTypeString() {
1102 $params = [
1103 'membership_contact_id' => $this->_contactID,
1104 'membership_type_id' => 'invalid',
1105 'join_date' => '2011-01-21',
1106 'start_date' => '2010-01-21',
1107 'end_date' => '2008-12-21',
1108 'source' => 'Payment',
1109 'is_override' => 1,
1110 'status_id' => $this->_membershipStatusID,
1111 ];
1112
1113 $this->callAPIFailure('membership', 'create', $params);
1114 }
1115
1116 /**
1117 * Test that if membership join date is not set it defaults to today.
1118 */
1119 public function testEmptyJoinDate() {
1120 unset($this->_params['join_date'], $this->_params['is_override']);
1121 $result = $this->callAPISuccess($this->_entity, 'create', $this->_params);
1122 $result = $this->callAPISuccess($this->_entity, 'getsingle', ['id' => $result['id']]);
1123 $this->assertEquals(date('Y-m-d', strtotime('now')), $result['join_date']);
1124 $this->assertEquals('2009-01-21', $result['start_date']);
1125 $this->assertEquals('2009-12-21', $result['end_date']);
1126 }
1127
1128 /**
1129 * Test that if membership start date is not set it defaults to correct end date.
1130 * - fixed
1131 */
1132 public function testEmptyStartDateFixed() {
1133 unset($this->_params['start_date'], $this->_params['is_override']);
1134 $this->_params['membership_type_id'] = $this->_membershipTypeID2;
1135 $result = $this->callAPISuccess($this->_entity, 'create', $this->_params);
1136 $result = $this->callAPISuccess($this->_entity, 'getsingle', ['id' => $result['id']]);
1137 $this->assertEquals('2009-01-21', $result['join_date']);
1138 $this->assertEquals('2008-03-01', $result['start_date']);
1139 $this->assertEquals('2009-12-21', $result['end_date']);
1140 }
1141
1142 /**
1143 * Test that if membership start date is not set it defaults to correct end date
1144 * - fixed
1145 */
1146 public function testEmptyStartEndDateFixedOneYear() {
1147 unset($this->_params['start_date'], $this->_params['is_override'], $this->_params['end_date']);
1148 $this->callAPISuccess('membership_type', 'create', ['id' => $this->_membershipTypeID2, 'duration_interval' => 1]);
1149 $this->_params['membership_type_id'] = $this->_membershipTypeID2;
1150 $result = $this->callAPISuccess($this->_entity, 'create', $this->_params);
1151 $result = $this->callAPISuccess($this->_entity, 'getsingle', ['id' => $result['id']]);
1152 $this->assertEquals('2009-01-21', $result['join_date']);
1153 $this->assertEquals('2008-03-01', $result['start_date']);
1154 $this->assertEquals('2010-02-28', $result['end_date']);
1155 }
1156
1157 /**
1158 * Test that if membership start date is not set it defaults to correct end date for fixed multi year memberships.
1159 */
1160 public function testEmptyStartEndDateFixedMultiYear() {
1161 unset($this->_params['start_date'], $this->_params['is_override'], $this->_params['end_date']);
1162 $this->callAPISuccess('membership_type', 'create', ['id' => $this->_membershipTypeID2, 'duration_interval' => 5]);
1163 $this->_params['membership_type_id'] = $this->_membershipTypeID2;
1164 $result = $this->callAPISuccess($this->_entity, 'create', $this->_params);
1165 $result = $this->callAPISuccess($this->_entity, 'getsingle', ['id' => $result['id']]);
1166 $this->assertEquals('2009-01-21', $result['join_date']);
1167 $this->assertEquals('2008-03-01', $result['start_date']);
1168 $this->assertEquals('2014-02-28', $result['end_date']);
1169 }
1170
1171 /**
1172 * CRM-18503 - Test membership join date is correctly set for fixed memberships.
1173 *
1174 * @throws \CRM_Core_Exception
1175 */
1176 public function testMembershipJoinDateFixed() {
1177 $memStatus = CRM_Member_PseudoConstant::membershipStatus();
1178 // Update the fixed membership type to 1 year duration.
1179 $this->callAPISuccess('membership_type', 'create', ['id' => $this->_membershipTypeID2, 'duration_interval' => 1]);
1180 $contactId = $this->createLoggedInUser();
1181 // Create membership with 'Pending' status.
1182 $params = [
1183 'contact_id' => $contactId,
1184 'membership_type_id' => $this->_membershipTypeID2,
1185 'source' => 'test membership',
1186 'is_pay_later' => 0,
1187 'status_id' => array_search('Pending', $memStatus),
1188 'skipStatusCal' => 1,
1189 'is_for_organization' => 1,
1190 ];
1191 $membership = CRM_Member_BAO_Membership::create($params);
1192
1193 // Update membership to 'Completed' and check the dates.
1194 $memParams = [
1195 'id' => $membership->id,
1196 'contact_id' => $contactId,
1197 'is_test' => 0,
1198 'membership_type_id' => $this->_membershipTypeID2,
1199 'num_terms' => 1,
1200 'status_id' => array_search('New', $memStatus),
1201 ];
1202 $result = $this->callAPISuccess('Membership', 'create', $memParams);
1203
1204 // Extend duration interval if join_date exceeds the rollover period.
1205 $joinDate = date('Y-m-d');
1206 $year = date('Y');
1207 $startDate = date('Y-m-d', strtotime(date('Y-03-01')));
1208 $rollOver = TRUE;
1209 if (strtotime($startDate) > time()) {
1210 $rollOver = FALSE;
1211 $startDate = date('Y-m-d', strtotime(date('Y-03-01') . '- 1 year'));
1212 }
1213 $membershipTypeDetails = CRM_Member_BAO_MembershipType::getMembershipTypeDetails($this->_membershipTypeID2);
1214 $fixedPeriodRollover = CRM_Member_BAO_MembershipType::isDuringFixedAnnualRolloverPeriod($joinDate, $membershipTypeDetails, $year, $startDate);
1215 $y = 1;
1216 if ($fixedPeriodRollover && $rollOver) {
1217 $y += 1;
1218 }
1219
1220 $expectedDates = [
1221 'join_date' => date('Ymd'),
1222 'start_date' => str_replace('-', '', $startDate),
1223 'end_date' => date('Ymd', strtotime(date('Y-03-01') . "+ {$y} year - 1 day")),
1224 ];
1225 foreach ($result['values'] as $values) {
1226 foreach ($expectedDates as $date => $val) {
1227 $this->assertEquals($val, $values[$date], "Failed asserting {$date} values");
1228 }
1229 }
1230 }
1231
1232 /**
1233 * Test correct end and start dates are calculated for fixed multi year memberships.
1234 *
1235 * The empty start date is calculated to be the start_date (1 Jan prior to the join_date - so 1 Jan 15)
1236 *
1237 * In this set our start date is after the start day and before the rollover day so we don't get an extra year
1238 * and we end one day before the rollover day. Start day is 1 Jan so we end on 31 Dec
1239 * and we add on 4 years rather than 5 because we are not after the rollover day - so we calculate 31 Dec 2019
1240 */
1241 public function testFixedMultiYearDateSetTwoEmptyStartEndDate() {
1242 unset($this->_params['start_date'], $this->_params['is_override'], $this->_params['end_date']);
1243
1244 $this->callAPISuccess('membership_type', 'create', [
1245 'id' => $this->_membershipTypeID2,
1246 'duration_interval' => 5,
1247 // Ie 1 Jan.
1248 'fixed_period_start_day' => '101',
1249 // Ie. 1 Nov.
1250 'fixed_period_rollover_day' => '1101',
1251 ]);
1252 $this->_params['membership_type_id'] = $this->_membershipTypeID2;
1253 $dates = [
1254 'join_date' => '28-Jan 2015',
1255 ];
1256 $result = $this->callAPISuccess($this->_entity, 'create', array_merge($this->_params, $dates));
1257 $result = $this->callAPISuccess($this->_entity, 'getsingle', ['id' => $result['id']]);
1258 $this->assertEquals('2015-01-28', $result['join_date']);
1259 $this->assertEquals('2015-01-01', $result['start_date']);
1260 $this->assertEquals('2019-12-31', $result['end_date']);
1261 }
1262
1263 /**
1264 * Test that correct end date is calculated for fixed multi year memberships and start date is not changed.
1265 *
1266 * In this set our start date is after the start day and before the rollover day so we don't get an extra year
1267 * and we end one day before the rollover day. Start day is 1 Jan so we end on 31 Dec
1268 * and we add on 4 years rather than 5 because we are not after the rollover day - so we calculate 31 Dec 2019
1269 */
1270 public function testFixedMultiYearDateSetTwoEmptyEndDate() {
1271 unset($this->_params['start_date'], $this->_params['is_override'], $this->_params['end_date']);
1272
1273 $this->callAPISuccess('membership_type', 'create', [
1274 'id' => $this->_membershipTypeID2,
1275 'duration_interval' => 5,
1276 // Ie 1 Jan.
1277 'fixed_period_start_day' => '101',
1278 // Ie. 1 Nov.
1279 'fixed_period_rollover_day' => '1101',
1280 ]);
1281 $this->_params['membership_type_id'] = $this->_membershipTypeID2;
1282 $dates = [
1283 'start_date' => '28-Jan 2015',
1284 'join_date' => '28-Jan 2015',
1285 ];
1286 $result = $this->callAPISuccess($this->_entity, 'create', array_merge($this->_params, $dates));
1287 $result = $this->callAPISuccess($this->_entity, 'getsingle', ['id' => $result['id']]);
1288 $this->assertEquals('2015-01-28', $result['join_date']);
1289 $this->assertEquals('2015-01-28', $result['start_date']);
1290 $this->assertEquals('2019-12-31', $result['end_date']);
1291 }
1292
1293 /**
1294 * Test correct end and start dates are calculated for fixed multi year memberships.
1295 *
1296 * The empty start date is calculated to be the start_date (1 Jan prior to the join_date - so 1 Jan 15)
1297 *
1298 * In this set our start date is after the start day and before the rollover day so we don't get an extra year
1299 * and we end one day before the rollover day. Start day is 1 Jan so we end on 31 Dec
1300 * and we add on <1 years rather than > 1 because we are not after the rollover day - so we calculate 31 Dec 2015
1301 */
1302 public function testFixedSingleYearDateSetTwoEmptyStartEndDate() {
1303 unset($this->_params['start_date'], $this->_params['is_override'], $this->_params['end_date']);
1304
1305 $this->callAPISuccess('membership_type', 'create', [
1306 'id' => $this->_membershipTypeID2,
1307 'duration_interval' => 1,
1308 // Ie 1 Jan.
1309 'fixed_period_start_day' => '101',
1310 // Ie. 1 Nov.
1311 'fixed_period_rollover_day' => '1101',
1312 ]);
1313 $this->_params['membership_type_id'] = $this->_membershipTypeID2;
1314 $dates = [
1315 'join_date' => '28-Jan 2015',
1316 ];
1317 $result = $this->callAPISuccess($this->_entity, 'create', array_merge($this->_params, $dates));
1318 $result = $this->callAPISuccess($this->_entity, 'getsingle', ['id' => $result['id']]);
1319 $this->assertEquals('2015-01-28', $result['join_date']);
1320 $this->assertEquals('2015-01-01', $result['start_date']);
1321 $this->assertEquals('2015-12-31', $result['end_date']);
1322 }
1323
1324 /**
1325 * Test correct end date for fixed single year memberships is calculated and start_date is not changed.
1326 *
1327 * In this set our start date is after the start day and before the rollover day so we don't get an extra year
1328 * and we end one day before the rollover day. Start day is 1 Jan so we end on 31 Dec
1329 * and we add on <1 years rather than > 1 because we are not after the rollover day - so we calculate 31 Dec 2015
1330 */
1331 public function testFixedSingleYearDateSetTwoEmptyEndDate() {
1332 unset($this->_params['start_date'], $this->_params['is_override'], $this->_params['end_date']);
1333
1334 $this->callAPISuccess('membership_type', 'create', [
1335 'id' => $this->_membershipTypeID2,
1336 'duration_interval' => 1,
1337 // Ie 1 Jan.
1338 'fixed_period_start_day' => '101',
1339 // Ie. 1 Nov.
1340 'fixed_period_rollover_day' => '1101',
1341 ]);
1342 $this->_params['membership_type_id'] = $this->_membershipTypeID2;
1343 $dates = [
1344 'start_date' => '28-Jan 2015',
1345 'join_date' => '28-Jan 2015',
1346 ];
1347 $result = $this->callAPISuccess($this->_entity, 'create', array_merge($this->_params, $dates));
1348 $result = $this->callAPISuccess($this->_entity, 'getsingle', ['id' => $result['id']]);
1349 $this->assertEquals('2015-01-28', $result['join_date']);
1350 $this->assertEquals('2015-01-28', $result['start_date']);
1351 $this->assertEquals('2015-12-31', $result['end_date']);
1352 }
1353
1354 /**
1355 * Test that correct end date is calculated for fixed multi year memberships and start date is not changed.
1356 *
1357 * In this set our start date is after the start day and after the rollover day so we do get an extra year
1358 * and we end one day before the rollover day. Start day is 1 Nov so we end on 31 Oct
1359 * and we add on 1 year we are after the rollover day - so we calculate 31 Oct 2016
1360 */
1361 public function testFixedSingleYearDateSetThreeEmptyEndDate() {
1362 unset($this->_params['start_date'], $this->_params['is_override'], $this->_params['end_date']);
1363
1364 $this->callAPISuccess('membership_type', 'create', [
1365 'id' => $this->_membershipTypeID2,
1366 'duration_interval' => 1,
1367 // Ie. 1 Nov.
1368 'fixed_period_start_day' => '1101',
1369 // Ie 1 Jan.
1370 'fixed_period_rollover_day' => '101',
1371 ]);
1372 $this->_params['membership_type_id'] = $this->_membershipTypeID2;
1373 $dates = [
1374 'start_date' => '28-Jan 2015',
1375 'join_date' => '28-Jan 2015',
1376 ];
1377 $result = $this->callAPISuccess($this->_entity, 'create', array_merge($this->_params, $dates));
1378 $result = $this->callAPISuccess($this->_entity, 'getsingle', ['id' => $result['id']]);
1379 $this->assertEquals('2015-01-28', $result['join_date']);
1380 $this->assertEquals('2015-01-28', $result['start_date']);
1381 $this->assertEquals('2016-10-31', $result['end_date']);
1382 }
1383
1384 /**
1385 * Test correct end and start dates are calculated for fixed multi year memberships.
1386 *
1387 * The empty start date is calculated to be the start_date (1 Nov prior to the join_date - so 1 Nov 14)
1388 *
1389 * In this set our start date is after the start day and after the rollover day so we do get an extra year
1390 * and we end one day before the rollover day. Start day is 1 Nov so we end on 31 Oct
1391 * and we add on 1 year we are after the rollover day - so we calculate 31 Oct 2016
1392 */
1393 public function testFixedSingleYearDateSetThreeEmptyStartEndDate() {
1394 unset($this->_params['start_date'], $this->_params['is_override'], $this->_params['end_date']);
1395
1396 $this->callAPISuccess('membership_type', 'create', [
1397 'id' => $this->_membershipTypeID2,
1398 'duration_interval' => 1,
1399 // Ie. 1 Nov.
1400 'fixed_period_start_day' => '1101',
1401 // Ie 1 Jan.
1402 'fixed_period_rollover_day' => '101',
1403 ]);
1404 $this->_params['membership_type_id'] = $this->_membershipTypeID2;
1405 $dates = [
1406 'join_date' => '28-Jan 2015',
1407 ];
1408 $result = $this->callAPISuccess($this->_entity, 'create', array_merge($this->_params, $dates));
1409 $result = $this->callAPISuccess($this->_entity, 'getsingle', ['id' => $result['id']]);
1410 $this->assertEquals('2015-01-28', $result['join_date']);
1411 $this->assertEquals('2014-11-01', $result['start_date']);
1412 $this->assertEquals('2016-10-31', $result['end_date']);
1413 }
1414
1415 /**
1416 * Test that correct end date is calculated for fixed multi year memberships and start date is not changed.
1417 *
1418 * In this set our start date is after the start day and after the rollover day so we do get an extra year
1419 * and we end one day before the rollover day. Start day is 1 Nov so we end on 31 Oct
1420 * and we add on 5 years we are after the rollover day - so we calculate 31 Oct 2020
1421 */
1422 public function testFixedMultiYearDateSetThreeEmptyEndDate() {
1423 unset($this->_params['start_date'], $this->_params['is_override'], $this->_params['end_date']);
1424
1425 $this->callAPISuccess('membership_type', 'create', [
1426 'id' => $this->_membershipTypeID2,
1427 'duration_interval' => 5,
1428 // Ie. 1 Nov.
1429 'fixed_period_start_day' => '1101',
1430 // Ie 1 Jan.
1431 'fixed_period_rollover_day' => '101',
1432 ]);
1433 $this->_params['membership_type_id'] = $this->_membershipTypeID2;
1434 $dates = [
1435 'start_date' => '28-Jan 2015',
1436 'join_date' => '28-Jan 2015',
1437 ];
1438 $result = $this->callAPISuccess($this->_entity, 'create', array_merge($this->_params, $dates));
1439 $result = $this->callAPISuccess($this->_entity, 'getsingle', ['id' => $result['id']]);
1440 $this->assertEquals('2015-01-28', $result['join_date']);
1441 $this->assertEquals('2015-01-28', $result['start_date']);
1442 $this->assertEquals('2020-10-31', $result['end_date']);
1443 }
1444
1445 /**
1446 * Test correct end and start dates are calculated for fixed multi year memberships.
1447 *
1448 * The empty start date is calculated to be the start_date (1 Nov prior to the join_date - so 1 Nov 14)
1449 *
1450 * The empty start date is calculated to be the start_date (1 Nov prior to the join_date - so 1 Nov 14)
1451 * In this set our join date is after the start day and after the rollover day so we do get an extra year
1452 * and we end one day before the rollover day. Start day is 1 Nov so we end on 31 Oct
1453 * and we add on 5 years we are after the rollover day - so we calculate 31 Oct 2020
1454 */
1455 public function testFixedMultiYearDateSetThreeEmptyStartEndDate() {
1456 unset($this->_params['start_date'], $this->_params['is_override'], $this->_params['end_date']);
1457
1458 $this->callAPISuccess('membership_type', 'create', [
1459 'id' => $this->_membershipTypeID2,
1460 'duration_interval' => 5,
1461 // Ie. 1 Nov.
1462 'fixed_period_start_day' => '1101',
1463 // Ie 1 Jan.
1464 'fixed_period_rollover_day' => '101',
1465 ]);
1466 $this->_params['membership_type_id'] = $this->_membershipTypeID2;
1467 $dates = [
1468 'join_date' => '28-Jan 2015',
1469 ];
1470 $result = $this->callAPISuccess($this->_entity, 'create', array_merge($this->_params, $dates));
1471 $result = $this->callAPISuccess($this->_entity, 'getsingle', ['id' => $result['id']]);
1472 $this->assertEquals('2015-01-28', $result['join_date']);
1473 $this->assertEquals('2014-11-01', $result['start_date']);
1474 $this->assertEquals('2020-10-31', $result['end_date']);
1475 }
1476
1477 /**
1478 * Test that if membership start date is not set it defaults to correct end date for fixed single year memberships.
1479 */
1480 public function testEmptyStartDateRolling() {
1481 unset($this->_params['start_date'], $this->_params['is_override']);
1482 $result = $this->callAPISuccess($this->_entity, 'create', $this->_params);
1483 $result = $this->callAPISuccess($this->_entity, 'getsingle', ['id' => $result['id']]);
1484 $this->assertEquals('2009-01-21', $result['join_date']);
1485 $this->assertEquals('2009-01-21', $result['start_date']);
1486 $this->assertEquals('2009-12-21', $result['end_date']);
1487 }
1488
1489 /**
1490 * Test that if membership end date is not set it defaults to correct end date.
1491 * - rolling
1492 */
1493 public function testEmptyEndDateFixed() {
1494 unset($this->_params['start_date'], $this->_params['is_override'], $this->_params['end_date']);
1495 $this->_params['membership_type_id'] = $this->_membershipTypeID2;
1496 $result = $this->callAPISuccess($this->_entity, 'create', $this->_params);
1497 $result = $this->callAPISuccess($this->_entity, 'getsingle', ['id' => $result['id']]);
1498 $this->assertEquals('2009-01-21', $result['join_date']);
1499 $this->assertEquals('2008-03-01', $result['start_date']);
1500 $this->assertEquals('2010-02-28', $result['end_date']);
1501 }
1502
1503 /**
1504 * Test that if membership end date is not set it defaults to correct end date.
1505 * - rolling
1506 */
1507 public function testEmptyEndDateRolling() {
1508 unset($this->_params['is_override'], $this->_params['end_date']);
1509 $this->_params['membership_type_id'] = $this->_membershipTypeID;
1510 $result = $this->callAPISuccess($this->_entity, 'create', $this->_params);
1511 $result = $this->callAPISuccess($this->_entity, 'getsingle', ['id' => $result['id']]);
1512 $this->assertEquals('2009-01-21', $result['join_date']);
1513 $this->assertEquals('2009-01-21', $result['start_date']);
1514 $this->assertEquals('2010-01-20', $result['end_date']);
1515 }
1516
1517 /**
1518 * Test that if dates are set they not over-ridden if id is passed in
1519 */
1520 public function testMembershipDatesNotOverridden() {
1521 $result = $this->callAPISuccess($this->_entity, 'create', $this->_params);
1522 unset($this->_params['end_date'], $this->_params['start_date']);
1523 $this->_params['id'] = $result['id'];
1524 $this->callAPISuccess($this->_entity, 'create', $this->_params);
1525 $result = $this->callAPISuccess($this->_entity, 'getsingle', ['id' => $result['id']]);
1526 $this->assertEquals('2009-01-21', $result['join_date']);
1527 $this->assertEquals('2009-01-21', $result['start_date']);
1528 $this->assertEquals('2009-12-21', $result['end_date']);
1529
1530 }
1531
1532 /**
1533 * Test that a contribution linked to multiple memberships results in all being updated.
1534 *
1535 * @throws \CRM_Core_Exception
1536 */
1537 public function testMultipleMembershipContribution() {
1538 $this->createMultipleMembershipOrder();
1539 $this->callAPISuccess('Payment', 'create', [
1540 'contribution_id' => $this->ids['Contribution'][0],
1541 'payment_instrument_id' => 'Check',
1542 'total_amount' => 400,
1543 ]);
1544 $memberships = $this->callAPISuccess('membership', 'get')['values'];
1545 $this->assertCount(2, $memberships);
1546 }
1547
1548 /**
1549 * Test that all membership types are returned when getoptions is called.
1550 *
1551 * This test locks in current behaviour where types for all domains are returned. It should possibly be domain
1552 * specific but that should only be done in conjunction with adding a hook to allow that to be altered as the
1553 * multisite use case expects the master domain to be able to see all sites.
1554 *
1555 * See CRM-17075.
1556 */
1557 public function testGetOptionsMembershipTypeID() {
1558 $options = $this->callAPISuccess('Membership', 'getoptions', ['field' => 'membership_type_id']);
1559 $this->assertEquals('Another one', array_pop($options['values']));
1560 $this->assertEquals('General', array_pop($options['values']));
1561 $this->assertEquals(NULL, array_pop($options['values']));
1562 }
1563
1564 }