Merge pull request #15948 from eileenmcnaughton/export_test
[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
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}