Commit | Line | Data |
---|---|---|
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 | */ | |
18 | class 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 | */ | |
47eea6b6 | 142 | public function testRemoveRelationshipTypeDuplicates($relationshipTypeList, $suffix, $expected, $description) { |
02e028a0 AS |
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 | } |