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