Merge pull request #19806 from eileenmcnaughton/msg_compat
[civicrm-core.git] / tests / phpunit / CRM / Contact / BAO / RelationshipTest.php
CommitLineData
02e028a0
AS
1<?php
2/*
7d61e75f
TO
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 +--------------------------------------------------------------------+
02e028a0
AS
10 */
11
12/**
13 * Test class for CRM_Contact_BAO_Relationship
14 *
15 * @package CiviCRM
16 * @group headless
17 */
18class CRM_Contact_BAO_RelationshipTest extends CiviUnitTestCase {
19
02e028a0
AS
20 /**
21 * Tears down the fixture, for example, closes a network connection.
22 *
23 * This method is called after a test is executed.
310c2031 24 *
25 * @throws \CRM_Core_Exception
02e028a0 26 */
594a9328 27 protected function tearDown(): void {
89e45979
MD
28 $this->quickCleanup([
29 'civicrm_relationship_type',
30 'civicrm_relationship',
39b959db 31 'civicrm_contact',
89e45979
MD
32 ]);
33
02e028a0
AS
34 parent::tearDown();
35 }
36
310c2031 37 /**
38 * Test Relationship Type Options Will Return Specified Type
39 *
40 * @throws \CRM_Core_Exception
41 */
89e45979
MD
42 public function testRelationshipTypeOptionsWillReturnSpecifiedType() {
43 $orgToOrgType = 'A_B_relationship';
44 $orgToOrgReverseType = 'B_A_relationship';
310c2031 45 $this->callAPISuccess('RelationshipType', 'create', [
89e45979
MD
46 'name_a_b' => $orgToOrgType,
47 'name_b_a' => $orgToOrgReverseType,
48 'contact_type_a' => 'Organization',
49 'contact_type_b' => 'Organization',
50 ]);
51
1ac9bb56
CW
52 $result = civicrm_api3('Relationship', 'getoptions', [
53 'field' => 'relationship_type_id',
54 'is_form' => TRUE,
55 'contact_type' => 'Organization',
56 ]);
57 $this->assertContains($orgToOrgType, $result['values']);
58 $this->assertContains($orgToOrgReverseType, $result['values']);
59
60 $result = civicrm_api3('Relationship', 'getoptions', [
61 'field' => 'relationship_type_id',
62 'is_form' => TRUE,
63 'contact_type' => 'Individual',
64 ]);
65
66 $this->assertNotContains($orgToOrgType, $result['values']);
67 $this->assertNotContains($orgToOrgReverseType, $result['values']);
89e45979
MD
68 }
69
70 public function testContactIdAndRelationshipIdWillBeUsedInFilter() {
71 $individual = civicrm_api3('Contact', 'create', [
72 'display_name' => 'Individual A',
73 'contact_type' => 'Individual',
74 ]);
75 $organization = civicrm_api3('Contact', 'create', [
76 'organization_name' => 'Organization B',
77 'contact_type' => 'Organization',
78 ]);
79
80 $personToOrgType = 'A_B_relationship';
81 $orgToPersonType = 'B_A_relationship';
82
83 $orgToPersonTypeId = civicrm_api3('RelationshipType', 'create', [
84 'name_a_b' => $personToOrgType,
85 'name_b_a' => $orgToPersonType,
86 'contact_type_a' => 'Individual',
87 'contact_type_b' => 'Organization',
88 ])['id'];
89
90 $personToPersonType = 'A_B_alt_relationship';
91 $personToPersonReverseType = 'B_A_alt_relationship';
92
93 civicrm_api3('RelationshipType', 'create', [
94 'name_a_b' => $personToPersonType,
95 'name_b_a' => $personToPersonReverseType,
96 'contact_type_a' => 'Individual',
97 'contact_type_b' => 'Individual',
98 ]);
99
100 // create a relationship individual => organization
101 $relationship = civicrm_api3('Relationship', 'create', [
102 'contact_id_a' => $individual['id'],
103 'contact_id_b' => $organization['id'],
104 'relationship_type_id' => $orgToPersonTypeId,
105 ]);
106
1ac9bb56
CW
107 $options = civicrm_api3('Relationship', 'getoptions', [
108 'field' => 'relationship_type_id',
109 'is_form' => TRUE,
89e45979 110 'relationship_id' => (string) $relationship['id'],
39b959db 111 'contact_id' => $individual['id'],
89e45979
MD
112 ]);
113
114 // for this relationship only individual=>organization is possible
1ac9bb56
CW
115 $this->assertContains($personToOrgType, $options['values']);
116 $this->assertNotContains($orgToPersonType, $options['values']);
89e45979
MD
117
118 // by passing relationship ID we know that the "B" side is an organization
1ac9bb56
CW
119 $this->assertNotContains($personToPersonType, $options['values']);
120 $this->assertNotContains($personToPersonReverseType, $options['values']);
89e45979 121
1ac9bb56
CW
122 $options = civicrm_api3('Relationship', 'getoptions', [
123 'field' => 'relationship_type_id',
124 'is_form' => TRUE,
39b959db 125 'contact_id' => $individual['id'],
89e45979
MD
126 ]);
127
128 // for this result we only know that "A" must be an individual
1ac9bb56
CW
129 $this->assertContains($personToOrgType, $options['values']);
130 $this->assertNotContains($orgToPersonType, $options['values']);
89e45979
MD
131
132 // unlike when we pass relationship type ID there is no filter by "B" type
1ac9bb56
CW
133 $this->assertContains($personToPersonType, $options['values']);
134 $this->assertContains($personToPersonReverseType, $options['values']);
89e45979
MD
135 }
136
02e028a0
AS
137 /**
138 * Test removeRelationshipTypeDuplicates method.
139 *
140 * @dataProvider getRelationshipTypeDuplicates
141 */
142 public function testRemoveRelationshipTypeDuplicates($relationshipTypeList, $suffix = NULL, $expected, $description) {
143 $result = CRM_Contact_BAO_Relationship::removeRelationshipTypeDuplicates($relationshipTypeList, $suffix);
144 $this->assertEquals($expected, $result, "Failure on set '$description'");
145 }
146
147 public function getRelationshipTypeDuplicates() {
9099cab3 148 $relationshipTypeList = [
02e028a0
AS
149 '1_a_b' => 'duplicate one',
150 '1_b_a' => 'duplicate one',
151 '2_a_b' => 'two a',
152 '2_b_a' => 'two b',
9099cab3
CW
153 ];
154 $data = [
155 [
02e028a0
AS
156 $relationshipTypeList,
157 'a_b',
9099cab3 158 [
02e028a0
AS
159 '1_a_b' => 'duplicate one',
160 '2_a_b' => 'two a',
161 '2_b_a' => 'two b',
9099cab3 162 ],
02e028a0 163 'With suffix a_b',
9099cab3
CW
164 ],
165 [
02e028a0
AS
166 $relationshipTypeList,
167 'b_a',
9099cab3 168 [
02e028a0
AS
169 '1_b_a' => 'duplicate one',
170 '2_a_b' => 'two a',
171 '2_b_a' => 'two b',
9099cab3 172 ],
02e028a0 173 'With suffix b_a',
9099cab3
CW
174 ],
175 [
02e028a0
AS
176 $relationshipTypeList,
177 NULL,
9099cab3 178 [
02e028a0
AS
179 '1_a_b' => 'duplicate one',
180 '2_a_b' => 'two a',
181 '2_b_a' => 'two b',
9099cab3 182 ],
02e028a0 183 'With suffix NULL',
9099cab3
CW
184 ],
185 [
02e028a0
AS
186 $relationshipTypeList,
187 NULL,
9099cab3 188 [
02e028a0
AS
189 '1_a_b' => 'duplicate one',
190 '2_a_b' => 'two a',
191 '2_b_a' => 'two b',
9099cab3 192 ],
02e028a0 193 'With suffix "" (empty string)',
9099cab3
CW
194 ],
195 ];
02e028a0
AS
196 return $data;
197 }
198
96c40ac7 199 /**
200 * Test that two similar memberships are not created for two relationships
201 *
202 * @throws \CRM_Core_Exception
203 */
204 public function testSingleMembershipForTwoRelationships() {
205 $individualID = $this->individualCreate(['display_name' => 'Individual A']);
206 $organisationID = $this->organizationCreate(['organization_name' => 'Organization B']);
207 $membershipOrganisationID = $this->organizationCreate(['organization_name' => 'Membership Organization']);
208 $orgToPersonTypeId1 = $this->relationshipTypeCreate(['name_a_b' => 'Inherited_Relationship_1_A_B', 'name_b_a' => 'Inherited_Relationship_1_B_A']);
209 $orgToPersonTypeId2 = $this->relationshipTypeCreate(['name_a_b' => 'Inherited_Relationship_2_A_B', 'name_b_a' => 'Inherited_Relationship_2_B_A']);
210
211 $membershipType = $this->callAPISuccess('MembershipType', 'create', [
212 'member_of_contact_id' => $membershipOrganisationID,
213 'financial_type_id' => 'Member Dues',
214 'duration_unit' => 'year',
215 'duration_interval' => 1,
216 'period_type' => 'rolling',
217 'name' => 'Inherited Membership',
218 'relationship_type_id' => [$orgToPersonTypeId1, $orgToPersonTypeId2],
1c7c69c5 219 'relationship_direction' => ['b_a', 'b_a'],
96c40ac7 220 ]);
221 $membershipType = $this->callAPISuccessGetSingle('MembershipType', ['id' => $membershipType['id']]);
222 // Check the metadata worked....
223 $this->assertEquals([$orgToPersonTypeId1, $orgToPersonTypeId2], $membershipType['relationship_type_id']);
1c7c69c5 224 $this->assertEquals(['b_a', 'b_a'], $membershipType['relationship_direction']);
96c40ac7 225
0951664a
SL
226 $startDate = date('Y-m') . '-19';
227 $joinDate = date('Y-m', strtotime('1 month ago')) . '-19';
96c40ac7 228 $this->callAPISuccess('Membership', 'create', [
229 'membership_type_id' => $membershipType['id'],
230 'contact_id' => $organisationID,
0951664a
SL
231 'start_date' => $startDate,
232 'join_date' => $joinDate,
96c40ac7 233 ]);
234
235 $relationshipOne = $this->callAPISuccess('Relationship', 'create', [
236 'contact_id_a' => $individualID,
237 'contact_id_b' => $organisationID,
238 'relationship_type_id' => $orgToPersonTypeId1,
239 ]);
1c7c69c5 240 $this->callAPISuccessGetCount('Membership', ['contact_id' => $individualID], 1);
96c40ac7 241 $relationshipTwo = $this->callAPISuccess('Relationship', 'create', [
242 'contact_id_a' => $individualID,
243 'contact_id_b' => $organisationID,
244 'relationship_type_id' => $orgToPersonTypeId2,
245 ]);
1c7c69c5 246 $this->callAPISuccessGetCount('Membership', ['contact_id' => $individualID], 1);
96c40ac7 247
f8569664 248 $inheritedMembership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $individualID]);
0951664a
SL
249 $this->assertEquals($startDate, $inheritedMembership['start_date']);
250 $this->assertEquals($joinDate, $inheritedMembership['join_date']);
f8569664 251
0a2663fd 252 $this->callAPISuccessGetCount('Membership', ['contact_id' => $organisationID], 1);
310c2031 253 // Disable the relationship & check the membership is not removed because the other relationship is still valid.
98fd6fc8 254 $relationshipOne['is_active'] = 0;
255 $this->callAPISuccess('Relationship', 'create', array_merge($relationshipOne, ['is_active' => 0]));
310c2031 256 $this->callAPISuccessGetCount('Membership', ['contact_id' => $individualID], 1);
257
96c40ac7 258 $relationshipTwo['is_active'] = 0;
259 $this->callAPISuccess('Relationship', 'create', $relationshipTwo);
310c2031 260 $this->callAPISuccessGetCount('Membership', ['contact_id' => $individualID], 0);
98fd6fc8 261
96c40ac7 262 $relationshipOne['is_active'] = 1;
263 $this->callAPISuccess('Relationship', 'create', $relationshipOne);
264 $this->callAPISuccessGetCount('Membership', ['contact_id' => $individualID], 1);
310c2031 265
96c40ac7 266 $relationshipTwo['is_active'] = 1;
267 $this->callAPISuccess('Relationship', 'create', $relationshipTwo);
268 $this->callAPISuccessGetCount('Membership', ['contact_id' => $individualID], 1);
269 $this->callAPISuccess('Relationship', 'delete', ['id' => $relationshipTwo['id']]);
270 $this->callAPISuccessGetCount('Membership', ['contact_id' => $individualID], 1);
271 $this->callAPISuccess('Relationship', 'delete', ['id' => $relationshipOne['id']]);
272 $this->callAPISuccessGetCount('Membership', ['contact_id' => $individualID], 0);
6345c936 273
96c40ac7 274 }
275
0d65e601
D
276 /**
277 * Test CRM_Contact_BAO_Relationship::add() function directly.
278 *
279 * In general it's preferred to use the Relationship-create api since it does
280 * checks and such before calling add(). There are already some good tests
281 * for the api, but since it does some more business logic after too the
282 * tests might not be checking exactly the same thing.
283 */
284 public function testBAOAdd() {
285 // add a new type
286 $relationship_type_id_1 = $this->relationshipTypeCreate([
287 'name_a_b' => 'Food poison tester is',
288 'name_b_a' => 'Food poison tester for',
289 'contact_type_a' => 'Individual',
290 'contact_type_b' => 'Individual',
291 ]);
292
293 // add some people
294 $contact_id_1 = $this->individualCreate();
295 $contact_id_2 = $this->individualCreate([], 1);
296
297 // create new relationship (using BAO)
298 $params = [
299 'relationship_type_id' => $relationship_type_id_1,
300 'contact_id_a' => $contact_id_1,
301 'contact_id_b' => $contact_id_2,
302 ];
303 $relationshipObj = CRM_Contact_BAO_Relationship::add($params);
304 $this->assertEquals($relationshipObj->relationship_type_id, $relationship_type_id_1);
305 $this->assertEquals($relationshipObj->contact_id_a, $contact_id_1);
306 $this->assertEquals($relationshipObj->contact_id_b, $contact_id_2);
307 $this->assertEquals($relationshipObj->is_active, 1);
308
309 // demonstrate PR 15103 - should fail before the patch and pass after
310 $today = date('Ymd');
311 $params = [
312 'id' => $relationshipObj->id,
313 'end_date' => $today,
314 ];
315 $relationshipObj = CRM_Contact_BAO_Relationship::add($params);
316 $this->assertEquals($relationshipObj->relationship_type_id, $relationship_type_id_1);
317 $this->assertEquals($relationshipObj->contact_id_a, $contact_id_1);
318 $this->assertEquals($relationshipObj->contact_id_b, $contact_id_2);
319 $this->assertEquals($relationshipObj->is_active, 1);
320 $this->assertEquals($relationshipObj->end_date, $today);
321 }
322
02e028a0 323}