Merge pull request #16591 from ixiam/dev/core#1575
[civicrm-core.git] / tests / phpunit / CRM / Member / BAO / 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 * Class CRM_Member_BAO_MembershipTest
14 * @group headless
15 */
16 class CRM_Member_BAO_MembershipTest extends CiviUnitTestCase {
17
18 public function setUp() {
19 parent::setUp();
20
21 $this->_contactID = $this->organizationCreate();
22 $this->_membershipTypeID = $this->membershipTypeCreate(['member_of_contact_id' => $this->_contactID]);
23 // add a random number to avoid silly conflicts with old data
24 $this->_membershipStatusID = $this->membershipStatusCreate('test status' . rand(1, 1000));
25 }
26
27 /**
28 * Tears down the fixture, for example, closes a network connection.
29 * This method is called after a test is executed.
30 *
31 * @throws \CRM_Core_Exception
32 */
33 public function tearDown() {
34 $this->membershipTypeDelete(['id' => $this->_membershipTypeID]);
35 $this->membershipStatusDelete($this->_membershipStatusID);
36 $this->contactDelete($this->_contactID);
37
38 $this->_contactID = $this->_membershipStatusID = $this->_membershipTypeID = NULL;
39 $this->quickCleanUpFinancialEntities();
40 $this->restoreMembershipTypes();
41 parent::tearDown();
42 }
43
44 /**
45 * Create membership type using given organization id.
46 *
47 * @param $organizationId
48 * @param bool $withRelationship
49 *
50 * @return array|int
51 * @throws \CRM_Core_Exception
52 */
53 private function createMembershipType($organizationId, $withRelationship = FALSE) {
54 $membershipType = $this->callAPISuccess('MembershipType', 'create', [
55 //Default domain ID
56 'domain_id' => 1,
57 'member_of_contact_id' => $organizationId,
58 'financial_type_id' => "Member Dues",
59 'duration_unit' => "year",
60 'duration_interval' => 1,
61 'period_type' => "rolling",
62 'name' => 'Organiation Membership Type',
63 'relationship_type_id' => ($withRelationship) ? 5 : NULL,
64 'relationship_direction' => ($withRelationship) ? 'b_a' : NULL,
65 ]);
66 return $membershipType["values"][$membershipType["id"]];
67 }
68
69 /**
70 * Get count of related memberships by parent membership id.
71 * @param $membershipId
72 * @return array|int
73 */
74 private function getRelatedMembershipsCount($membershipId) {
75 return $this->callAPISuccess("Membership", "getcount", [
76 'owner_membership_id' => $membershipId,
77 ]);
78 }
79
80 /**
81 * Test to delete related membership when type of parent memebrship is changed which does not have relation type associated.
82 * @throws CRM_Core_Exception
83 */
84 public function testDeleteRelatedMembershipsOnParentTypeChanged() {
85
86 $contactId = $this->individualCreate();
87 $membershipOrganizationId = $this->organizationCreate();
88 $organizationId = $this->organizationCreate();
89
90 // Create relationship between organization and individual contact
91 $this->callAPISuccess('Relationship', 'create', [
92 // Employer of relationship
93 'relationship_type_id' => 5,
94 'contact_id_a' => $contactId,
95 'contact_id_b' => $organizationId,
96 'is_active' => 1,
97 ]);
98
99 // Create two membership types one with relationship and one without.
100 $membershipTypeWithRelationship = $this->createMembershipType($membershipOrganizationId, TRUE);
101 $membershipTypeWithoutRelationship = $this->createMembershipType($membershipOrganizationId);
102
103 // Creating membership of organisation
104 $membership = $this->callAPISuccess("Membership", "create", [
105 'membership_type_id' => $membershipTypeWithRelationship["id"],
106 'contact_id' => $organizationId,
107 'status_id' => $this->_membershipStatusID,
108 ]);
109
110 $membership = $membership['values'][$membership["id"]];
111
112 // Check count of related memberships. It should be one for individual contact.
113 $relatedMembershipsCount = $this->getRelatedMembershipsCount($membership["id"]);
114 $this->assertEquals(1, $relatedMembershipsCount, 'Related membership count should be 1.');
115
116 // Update membership by changing it's type. New membership type is without relationship.
117 $membership["membership_type_id"] = $membershipTypeWithoutRelationship["id"];
118 $updatedMembership = $this->callAPISuccess("Membership", "create", $membership);
119
120 // Check count of related memberships again. It should be zero as we changed the membership type.
121 $relatedMembershipsCount = $this->getRelatedMembershipsCount($membership["id"]);
122 $this->assertEquals(0, $relatedMembershipsCount, 'Related membership count should be 0.');
123
124 // Clean up: Delete membership
125 $this->membershipDelete($membership["id"]);
126 }
127
128 public function testCreate() {
129
130 list($contactId, $membershipId) = $this->setupMembership();
131
132 // Now call create() to modify an existing Membership
133 $params = [
134 'contact_id' => $contactId,
135 'membership_type_id' => $this->_membershipTypeID,
136 'join_date' => date('Ymd', strtotime('2006-01-21')),
137 'start_date' => date('Ymd', strtotime('2006-01-21')),
138 'end_date' => date('Ymd', strtotime('2006-12-21')),
139 'source' => 'Payment',
140 'is_override' => 1,
141 'status_id' => $this->_membershipStatusID,
142 ];
143 $ids = [
144 'membership' => $membershipId,
145 ];
146 CRM_Member_BAO_Membership::create($params, $ids);
147
148 $membershipTypeId = $this->assertDBNotNull('CRM_Member_BAO_Membership', $contactId,
149 'membership_type_id', 'contact_id',
150 'Database check on updated membership record.'
151 );
152 $this->assertEquals($membershipTypeId, $this->_membershipTypeID, 'Verify membership type id is fetched.');
153
154 $this->membershipDelete($membershipId);
155 $this->contactDelete($contactId);
156 }
157
158 public function testGetValues() {
159 // $this->markTestSkipped( 'causes mysterious exit, needs fixing!' );
160 // Calculate membership dates based on the current date
161 $now = time();
162 $year_from_now = $now + (365 * 24 * 60 * 60);
163 $last_month = $now - (30 * 24 * 60 * 60);
164 $year_from_last_month = $last_month + (365 * 24 * 60 * 60);
165
166 $contactId = $this->individualCreate();
167
168 $params = [
169 'contact_id' => $contactId,
170 'membership_type_id' => $this->_membershipTypeID,
171 'join_date' => date('Ymd'),
172 'start_date' => date('Ymd'),
173 'end_date' => date('Ymd', $year_from_now),
174 'source' => 'Payment',
175 'is_override' => 1,
176 'status_id' => $this->_membershipStatusID,
177 ];
178
179 $ids = [];
180 CRM_Member_BAO_Membership::create($params, $ids);
181
182 $membershipId1 = $this->assertDBNotNull('CRM_Member_BAO_Membership', $contactId, 'id',
183 'contact_id', 'Database check for created membership.'
184 );
185
186 $params = [
187 'contact_id' => $contactId,
188 'membership_type_id' => $this->_membershipTypeID,
189 'join_date' => date('Ymd', $last_month),
190 'start_date' => date('Ymd', $last_month),
191 'end_date' => date('Ymd', $year_from_last_month),
192 'source' => 'Source123',
193 'is_override' => 0,
194 'status_id' => $this->_membershipStatusID,
195 ];
196 $ids = [];
197 CRM_Member_BAO_Membership::create($params, $ids);
198
199 $membershipId2 = $this->assertDBNotNull('CRM_Member_BAO_Membership', 'source123', 'id',
200 'source', 'Database check for created membership.'
201 );
202
203 $membership = ['contact_id' => $contactId];
204 $membershipValues = [];
205 CRM_Member_BAO_Membership::getValues($membership, $membershipValues, TRUE);
206
207 $this->assertEquals($membershipValues[$membershipId1]['membership_id'], $membershipId1, 'Verify membership record 1 is fetched.');
208
209 $this->assertEquals($membershipValues[$membershipId2]['membership_id'], $membershipId2, 'Verify membership record 2 is fetched.');
210
211 $this->membershipDelete($membershipId1);
212 $this->membershipDelete($membershipId2);
213 $this->contactDelete($contactId);
214 }
215
216 public function testRetrieve() {
217 list($contactId, $membershipId) = $this->setupMembership();
218 $params = ['id' => $membershipId];
219 $values = [];
220 CRM_Member_BAO_Membership::retrieve($params, $values);
221 $this->assertEquals($values['id'], $membershipId, 'Verify membership record is retrieved.');
222
223 $this->membershipDelete($membershipId);
224 $this->contactDelete($contactId);
225 }
226
227 public function testActiveMembers() {
228 $contactId = $this->individualCreate();
229
230 $params = [
231 'contact_id' => $contactId,
232 'membership_type_id' => $this->_membershipTypeID,
233 'join_date' => date('Ymd', strtotime('2006-01-21')),
234 'start_date' => date('Ymd', strtotime('2006-01-21')),
235 'end_date' => date('Ymd', strtotime('2006-12-21')),
236 'source' => 'Payment',
237 'is_override' => 1,
238 'status_id' => $this->_membershipStatusID,
239 ];
240 $ids = [];
241 CRM_Member_BAO_Membership::create($params, $ids);
242
243 $membershipId1 = $this->assertDBNotNull('CRM_Member_BAO_Membership', $contactId, 'id',
244 'contact_id', 'Database check for created membership.'
245 );
246
247 $params = ['id' => $membershipId1];
248 $values1 = [];
249 CRM_Member_BAO_Membership::retrieve($params, $values1);
250 $membership = [$membershipId1 => $values1];
251
252 $params = [
253 'contact_id' => $contactId,
254 'membership_type_id' => $this->_membershipTypeID,
255 'join_date' => date('Ymd', strtotime('2006-01-21')),
256 'start_date' => date('Ymd', strtotime('2006-01-21')),
257 'end_date' => date('Ymd', strtotime('2006-12-21')),
258 'source' => 'PaySource',
259 'is_override' => 1,
260 'status_id' => $this->_membershipStatusID,
261 ];
262 $ids = [];
263 CRM_Member_BAO_Membership::create($params, $ids);
264
265 $membershipId2 = $this->assertDBNotNull('CRM_Member_BAO_Membership', 'PaySource', 'id',
266 'source', 'Database check for created membership.'
267 );
268
269 $params = ['id' => $membershipId2];
270 $values2 = [];
271 CRM_Member_BAO_Membership::retrieve($params, $values2);
272 $membership[$membershipId2] = $values2;
273
274 $activeMembers = CRM_Member_BAO_Membership::activeMembers($membership);
275 $inActiveMembers = CRM_Member_BAO_Membership::activeMembers($membership, 'inactive');
276
277 $this->assertEquals($activeMembers[$membershipId1]['id'], $membership[$membershipId1]['id'], 'Verify active membership record is retrieved.');
278 $this->assertEquals($activeMembers[$membershipId2]['id'], $membership[$membershipId2]['id'], 'Verify active membership record is retrieved.');
279
280 $this->assertEquals(0, count($inActiveMembers), 'Verify No inactive membership record is retrieved.');
281
282 $this->membershipDelete($membershipId1);
283 $this->membershipDelete($membershipId2);
284 $this->contactDelete($contactId);
285 }
286
287 public function testDeleteMembership() {
288 list($contactId, $membershipId) = $this->setupMembership();
289 CRM_Member_BAO_Membership::del($membershipId);
290
291 $this->assertDBNull('CRM_Member_BAO_Membership', $contactId, 'id',
292 'contact_id', 'Database check for deleted membership.'
293 );
294 $this->assertDBNull('CRM_Price_BAO_LineItem', $membershipId, 'id',
295 'entity_id', 'Database check for deleted line item.'
296 );
297 $this->contactDelete($contactId);
298 }
299
300 public function testGetContactMembership() {
301 list($contactId, $membershipId) = $this->setupMembership();
302
303 $membership = CRM_Member_BAO_Membership::getContactMembership($contactId, $this->_membershipTypeID, FALSE);
304
305 $this->assertEquals($membership['id'], $membershipId, 'Verify membership record is retrieved.');
306
307 $this->membershipDelete($membershipId);
308 $this->contactDelete($contactId);
309 }
310
311 /**
312 * Get the contribution.
313 * page id from the membership record
314 */
315 public function testgetContributionPageId() {
316 list($contactId, $membershipId) = $this->setupMembership();
317 $membership[$membershipId]['renewPageId'] = CRM_Member_BAO_Membership::getContributionPageId($membershipId);
318
319 $this->membershipDelete($membershipId);
320 $this->contactDelete($contactId);
321 }
322
323 /**
324 * Get membership joins/renewals
325 * for a specified membership
326 * type.
327 */
328 public function testgetMembershipStarts() {
329 list($contactId, $membershipId) = $this->setupMembership();
330 $yearStart = date('Y') . '0101';
331 $currentDate = date('Ymd');
332 CRM_Member_BAO_Membership::getMembershipStarts($this->_membershipTypeID, $yearStart, $currentDate);
333
334 $this->membershipDelete($membershipId);
335 $this->contactDelete($contactId);
336 }
337
338 /**
339 * Get a count of membership for a specified membership type,
340 * optionally for a specified date.
341 */
342 public function testGetMembershipCount() {
343 list($contactId, $membershipId) = $this->setupMembership();
344 $currentDate = date('Ymd');
345 $test = 0;
346 CRM_Member_BAO_Membership::getMembershipCount($this->_membershipTypeID, $currentDate, $test);
347
348 $this->membershipDelete($membershipId);
349 $this->contactDelete($contactId);
350 }
351
352 /**
353 * Checkup sort name function.
354 */
355 public function testSortName() {
356 $contactId = $this->individualCreate();
357
358 $params = [
359 'contact_id' => $contactId,
360 'membership_type_id' => $this->_membershipTypeID,
361 'join_date' => '2006-01-21',
362 'start_date' => '2006-01-21',
363 'end_date' => '2006-12-21',
364 'source' => 'Payment',
365 'is_override' => 1,
366 'status_id' => $this->_membershipStatusID,
367 ];
368
369 $membership = $this->callAPISuccess('Membership', 'create', $params);
370
371 $this->assertEquals('Anderson, Anthony', CRM_Member_BAO_Membership::sortName($membership['id']));
372
373 $this->membershipDelete($membership['id']);
374 $this->contactDelete($contactId);
375 }
376
377 /**
378 * Delete related memberships.
379 */
380 public function testdeleteRelatedMemberships() {
381 list($contactId, $membershipId) = $this->setupMembership();
382
383 CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipId);
384
385 $this->membershipDelete($membershipId);
386 $this->contactDelete($contactId);
387 }
388
389 /**
390 * Renew membership with change in membership type.
391 *
392 * @fixme Note that this test fails when today is August 29 2019 (and maybe other years?):
393 * Verify correct end date is calculated after membership renewal
394 * Failed asserting that two strings are equal.
395 * Expected-'2021-03-01'
396 * Actual+'2021-02-28'
397 * /home/jenkins/bknix-dfl/build/core-15165-73etc/web/sites/all/modules/civicrm/tests/phpunit/CRM/Member/BAO/MembershipTest.php:609
398 */
399 public function testRenewMembership() {
400 $contactId = $this->individualCreate();
401 $joinDate = $startDate = date("Ymd", strtotime(date("Ymd") . " -6 month"));
402 $endDate = date("Ymd", strtotime($joinDate . " +1 year -1 day"));
403 $params = [
404 'contact_id' => $contactId,
405 'membership_type_id' => $this->_membershipTypeID,
406 'join_date' => $joinDate,
407 'start_date' => $startDate,
408 'end_date' => $endDate,
409 'source' => 'Payment',
410 'is_override' => 1,
411 'status_id' => $this->_membershipStatusID,
412 ];
413 $ids = [];
414 $membership = CRM_Member_BAO_Membership::create($params, $ids);
415 $membershipId = $this->assertDBNotNull('CRM_Member_BAO_Membership', $contactId, 'id',
416 'contact_id', 'Database check for created membership.'
417 );
418
419 $this->assertDBNotNull('CRM_Member_BAO_MembershipLog',
420 $membership->id,
421 'id',
422 'membership_id',
423 'Database checked on membershiplog record.'
424 );
425
426 // this is a test and we dont want qfKey generation / validation
427 // easier to suppress it, than change core code
428 $config = CRM_Core_Config::singleton();
429 $config->keyDisable = TRUE;
430
431 $isTestMembership = 0;
432 list($MembershipRenew) = CRM_Member_BAO_Membership::processMembership(
433 $contactId,
434 $this->_membershipTypeID,
435 $isTestMembership,
436 NULL,
437 NULL,
438 NULL,
439 1,
440 FALSE,
441 NULL,
442 NULL,
443 FALSE,
444 NULL,
445 NULL
446 );
447 $endDate = date("Y-m-d", strtotime($membership->end_date . " +1 year"));
448
449 $this->assertDBNotNull('CRM_Member_BAO_MembershipLog',
450 $MembershipRenew->id,
451 'id',
452 'membership_id',
453 'Database checked on membershiplog record.'
454 );
455 $this->assertEquals($this->_membershipTypeID, $MembershipRenew->membership_type_id, 'Verify membership type is changed during renewal.');
456 $this->assertEquals($endDate, $MembershipRenew->end_date, 'Verify correct end date is calculated after membership renewal');
457
458 $this->membershipDelete($membershipId);
459 $this->contactDelete($contactId);
460 }
461
462 /**
463 * Renew stale membership.
464 *
465 * @throws \CRM_Core_Exception
466 * @throws \CiviCRM_API3_Exception
467 */
468 public function testStaleMembership() {
469 $statusId = 3;
470 $contactId = $this->individualCreate();
471 $joinDate = $startDate = date("Ymd", strtotime(date("Ymd") . " -1 year -15 days"));
472 $endDate = date('Ymd', strtotime($joinDate . " +1 year -1 day"));
473 $params = [
474 'contact_id' => $contactId,
475 'membership_type_id' => $this->_membershipTypeID,
476 'join_date' => $joinDate,
477 'start_date' => $startDate,
478 'end_date' => $endDate,
479 'source' => 'Payment',
480 'status_id' => $statusId,
481 ];
482
483 $ids = [];
484 $membership = CRM_Member_BAO_Membership::create($params, $ids);
485
486 $membershipId = $this->assertDBNotNull('CRM_Member_BAO_Membership', $contactId, 'id',
487 'contact_id', 'Database check for created membership.'
488 );
489
490 $this->assertEquals($membership->status_id, $statusId, 'Verify correct status id is calculated.');
491 $this->assertEquals($membership->membership_type_id, $this->_membershipTypeID,
492 'Verify correct membership type id.'
493 );
494
495 //verify all dates.
496 $dates = [
497 'startDate' => 'start_date',
498 'joinDate' => 'join_date',
499 'endDate' => 'end_date',
500 ];
501
502 foreach ($dates as $date => $dbDate) {
503 $this->assertEquals($membership->$dbDate, $$date,
504 "Verify correct {$date} is present."
505 );
506 }
507
508 $this->assertDBNotNull('CRM_Member_BAO_MembershipLog',
509 $membership->id,
510 'id',
511 'membership_id',
512 'Database checked on membership log record.'
513 );
514
515 list($MembershipRenew) = CRM_Member_BAO_Membership::processMembership(
516 $contactId,
517 $this->_membershipTypeID,
518 FALSE,
519 FALSE,
520 NULL,
521 NULL,
522 NULL,
523 1,
524 NULL,
525 NULL,
526 NULL,
527 FALSE,
528 NULL
529 );
530
531 $this->assertDBNotNull('CRM_Member_BAO_MembershipLog',
532 $MembershipRenew->id,
533 'id',
534 'membership_id',
535 'Database checked on membership log record.'
536 );
537
538 $this->membershipDelete($membershipId);
539 $this->contactDelete($contactId);
540 }
541
542 public function testUpdateAllMembershipStatusConvertExpiredOverriddenStatusToNormal() {
543 $params = [
544 'contact_id' => $this->individualCreate(),
545 'membership_type_id' => $this->_membershipTypeID,
546 'join_date' => date('Ymd', time()),
547 'start_date' => date('Ymd', time()),
548 'end_date' => date('Ymd', strtotime('+1 year')),
549 'source' => 'Payment',
550 'is_override' => 1,
551 'status_override_end_date' => date('Ymd', strtotime('-1 day')),
552 'status_id' => $this->_membershipStatusID,
553 ];
554 $ids = [];
555 $createdMembership = CRM_Member_BAO_Membership::create($params, $ids);
556
557 CRM_Member_BAO_Membership::updateAllMembershipStatus();
558
559 $membershipAfterProcess = civicrm_api3('Membership', 'get', [
560 'sequential' => 1,
561 'id' => $createdMembership->id,
562 'return' => ['id', 'is_override', 'status_override_end_date'],
563 ])['values'][0];
564
565 $this->assertEquals($createdMembership->id, $membershipAfterProcess['id']);
566 $this->assertArrayNotHasKey('is_override', $membershipAfterProcess);
567 $this->assertArrayNotHasKey('status_override_end_date', $membershipAfterProcess);
568 }
569
570 public function testUpdateAllMembershipStatusHandleOverriddenWithEndOverrideDateEqualTodayAsExpired() {
571 $params = [
572 'contact_id' => $this->individualCreate(),
573 'membership_type_id' => $this->_membershipTypeID,
574 'join_date' => date('Ymd', time()),
575 'start_date' => date('Ymd', time()),
576 'end_date' => date('Ymd', strtotime('+1 year')),
577 'source' => 'Payment',
578 'is_override' => 1,
579 'status_override_end_date' => date('Ymd', time()),
580 'status_id' => $this->_membershipStatusID,
581 ];
582 $ids = [];
583 $createdMembership = CRM_Member_BAO_Membership::create($params, $ids);
584
585 CRM_Member_BAO_Membership::updateAllMembershipStatus();
586
587 $membershipAfterProcess = civicrm_api3('Membership', 'get', [
588 'sequential' => 1,
589 'id' => $createdMembership->id,
590 'return' => ['id', 'is_override', 'status_override_end_date'],
591 ])['values'][0];
592
593 $this->assertEquals($createdMembership->id, $membershipAfterProcess['id']);
594 $this->assertArrayNotHasKey('is_override', $membershipAfterProcess);
595 $this->assertArrayNotHasKey('status_override_end_date', $membershipAfterProcess);
596 }
597
598 public function testUpdateAllMembershipStatusDoesNotConvertOverridenMembershipWithoutEndOverrideDateToNormal() {
599 $params = [
600 'contact_id' => $this->individualCreate(),
601 'membership_type_id' => $this->_membershipTypeID,
602 'join_date' => date('Ymd', time()),
603 'start_date' => date('Ymd', time()),
604 'end_date' => date('Ymd', strtotime('+1 year')),
605 'source' => 'Payment',
606 'is_override' => 1,
607 'status_id' => $this->_membershipStatusID,
608 ];
609 $ids = [];
610 $createdMembership = CRM_Member_BAO_Membership::create($params, $ids);
611
612 CRM_Member_BAO_Membership::updateAllMembershipStatus();
613
614 $membershipAfterProcess = civicrm_api3('Membership', 'get', [
615 'sequential' => 1,
616 'id' => $createdMembership->id,
617 'return' => ['id', 'is_override', 'status_override_end_date'],
618 ])['values'][0];
619
620 $this->assertEquals($createdMembership->id, $membershipAfterProcess['id']);
621 $this->assertEquals(1, $membershipAfterProcess['is_override']);
622 }
623
624 /**
625 * @throws \CRM_Core_Exception
626 */
627 public function testMembershipPaymentForSingleContributionMultipleMembership() {
628 $membershipTypeID1 = $this->membershipTypeCreate(['name' => 'Parent']);
629 $membershipTypeID2 = $this->membershipTypeCreate(['name' => 'Child']);
630 $financialTypeId = $this->getFinancialTypeId('Member Dues');
631 $priceSet = $this->callAPISuccess('price_set', 'create', [
632 'is_quick_config' => 0,
633 'extends' => 'CiviMember',
634 'financial_type_id' => $financialTypeId,
635 'title' => 'Family Membership',
636 ]);
637 $priceSetID = $priceSet['id'];
638 $priceField = $this->callAPISuccess('price_field', 'create', [
639 'price_set_id' => $priceSetID,
640 'label' => 'Memberships',
641 'html_type' => 'Radio',
642 ]);
643 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', [
644 'price_set_id' => $priceSetID,
645 'price_field_id' => $priceField['id'],
646 'label' => 'Parent',
647 'amount' => 100,
648 'financial_type_id' => $financialTypeId,
649 'membership_type_id' => $membershipTypeID1,
650 'membership_num_terms' => 1,
651 ]);
652 $priceFieldValueId = [1 => $priceFieldValue['id']];
653 $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', [
654 'price_set_id' => $priceSetID,
655 'price_field_id' => $priceField['id'],
656 'label' => 'Child',
657 'amount' => 50,
658 'financial_type_id' => $financialTypeId,
659 'membership_type_id' => $membershipTypeID2,
660 'membership_num_terms' => 1,
661 ]);
662 $priceFieldValueId[2] = $priceFieldValue['id'];
663 $parentContactId = $this->individualCreate();
664 $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', [
665 'contact_id' => $parentContactId,
666 'amount' => 150,
667 'frequency_unit' => 'day',
668 'frequency_interval' => 1,
669 'installments' => 2,
670 'start_date' => 'yesterday',
671 'create_date' => 'yesterday',
672 'modified_date' => 'yesterday',
673 'cancel_date' => NULL,
674 'end_date' => '+ 2 weeks',
675 'processor_id' => '643411460836',
676 'trxn_id' => 'e0d0808e26f3e661c6c18eb7c039d363',
677 'invoice_id' => 'e0d0808e26f3e661c6c18eb7c039d363',
678 'contribution_status_id' => 'In Progress',
679 'cycle_day' => 1,
680 'next_sched_contribution_date' => '+ 1 week',
681 'auto_renew' => 0,
682 'currency' => 'USD',
683 'payment_processor_id' => $this->paymentProcessorCreate(),
684 'financial_type_id' => $financialTypeId,
685 'payment_instrument_id' => 'Credit Card',
686 ]);
687
688 $params[] = [
689 'contact_id' => $this->individualCreate(),
690 'membership_type_id' => $membershipTypeID2,
691 'contribution_recur_id' => $contributionRecur['id'],
692 'join_date' => date('Ymd', time()),
693 'start_date' => date('Ymd', time()),
694 'end_date' => date('Ymd', strtotime('+1 year')),
695 'source' => 'Payment',
696 ];
697 $params[] = [
698 'contact_id' => $this->individualCreate(),
699 'membership_type_id' => $membershipTypeID2,
700 'contribution_recur_id' => $contributionRecur['id'],
701 'join_date' => date('Ymd', time()),
702 'start_date' => date('Ymd', time()),
703 'end_date' => date('Ymd', strtotime('+1 year')),
704 'source' => 'Payment',
705 ];
706
707 foreach ($params as $key => $param) {
708 $this->callAPISuccess('membership', 'create', $param);
709 }
710
711 $contribution = $this->callAPISuccess('Order', 'create', [
712 'total_amount' => 150,
713 'contribution_recur_id' => $contributionRecur['id'],
714 'currency' => 'USD',
715 'contact_id' => $parentContactId,
716 'financial_type_id' => $financialTypeId,
717 'contribution_status_id' => 'Pending',
718 'is_recur' => TRUE,
719 'api.Payment.create' => ['total_amount' => 150],
720 'line_items' => [
721 [
722 'line_item' => [
723 0 => [
724 'price_field_id' => $priceField['id'],
725 'price_field_value_id' => $priceFieldValueId[1],
726 'label' => 'Parent',
727 'membership_type_id' => $membershipTypeID1,
728 'qty' => 1,
729 'unit_price' => 100,
730 'line_total' => 100,
731 'financial_type_id' => $financialTypeId,
732 'entity_table' => 'civicrm_membership',
733 ],
734 1 => [
735 'price_field_id' => $priceField['id'],
736 'price_field_value_id' => $priceFieldValueId[2],
737 'label' => 'Child',
738 'qty' => 1,
739 'unit_price' => 50,
740 'line_total' => 50,
741 'membership_type_id' => $membershipTypeID2,
742 'financial_type_id' => $financialTypeId,
743 'entity_table' => 'civicrm_membership',
744 ],
745 ],
746 ],
747 ],
748 ]);
749 $params[] = [
750 'contact_id' => $parentContactId,
751 'membership_type_id' => $membershipTypeID1,
752 'contribution_recur_id' => $contributionRecur['id'],
753 'join_date' => date('Ymd', time()),
754 'start_date' => date('Ymd', time()),
755 'end_date' => date('Ymd', strtotime('+1 year')),
756 'skipLineItem' => TRUE,
757 'source' => 'Payment',
758 ];
759
760 $this->callAPISuccess('contribution', 'repeattransaction', [
761 'original_contribution_id' => $contribution['id'],
762 'contribution_status_id' => 'Completed',
763 ]);
764 $this->callAPISuccessGetCount('Contribution', [], 2);
765 // @todo this fails depending on what tests it is run with due some bad stuff in Membership.create
766 // It needs to be addressed but might involve the switch to ORDER. Membership BAO does bad line item stuff.
767 // $this->callAPISuccessGetCount('LineItem', [], 6);
768 $this->membershipTypeDelete(['id' => $membershipTypeID1]);
769 $this->membershipTypeDelete(['id' => $membershipTypeID2]);
770 $this->validateAllPayments();
771 $this->validateAllContributions();
772 }
773
774 /**
775 * Test the buildMembershipTypeValues function.
776 *
777 * @throws \CiviCRM_API3_Exception
778 */
779 public function testBuildMembershipTypeValues() {
780 $this->restoreMembershipTypes();
781 $form = new CRM_Core_Form();
782 $values = CRM_Member_BAO_Membership::buildMembershipTypeValues($form);
783 $this->assertEquals([
784 'id' => '1',
785 'minimum_fee' => '100.000000000',
786 'name' => 'General',
787 'is_active' => '1',
788 'description' => 'Regular annual membership.',
789 'financial_type_id' => '2',
790 'auto_renew' => '0',
791 'member_of_contact_id' => $values[1]['member_of_contact_id'],
792 'relationship_type_id' => [7],
793 'relationship_direction' => ['b_a'],
794 'max_related' => NULL,
795 'duration_unit' => 'year',
796 'duration_interval' => '2',
797 'domain_id' => '1',
798 'period_type' => 'rolling',
799 'visibility' => 'Public',
800 'weight' => '1',
801 'tax_rate' => 0.0,
802 'minimum_fee_with_tax' => 100.0,
803 ], $values[1]);
804 }
805
806 /**
807 * @return array
808 * @throws \CRM_Core_Exception
809 * @throws \CiviCRM_API3_Exception
810 */
811 protected function setupMembership(): array {
812 $contactId = $this->individualCreate();
813
814 $params = [
815 'contact_id' => $contactId,
816 'membership_type_id' => $this->_membershipTypeID,
817 'join_date' => date('Ymd', strtotime('2006-01-21')),
818 'start_date' => date('Ymd', strtotime('2006-01-21')),
819 'end_date' => date('Ymd', strtotime('2006-12-21')),
820 'source' => 'Payment',
821 'is_override' => 1,
822 'status_id' => $this->_membershipStatusID,
823 ];
824 $ids = [];
825 CRM_Member_BAO_Membership::create($params, $ids);
826
827 $membershipId = $this->assertDBNotNull('CRM_Member_BAO_Membership', $contactId, 'id',
828 'contact_id', 'Database check for created membership.'
829 );
830 return [$contactId, $membershipId];
831 }
832
833 }