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