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