Commit | Line | Data |
---|---|---|
0622d221 | 1 | <?php |
0622d221 | 2 | |
3 | /** | |
4 | * Class CRM_Dedupe_DedupeMergerTest | |
acb109b7 | 5 | * @group headless |
0622d221 | 6 | */ |
7 | class CRM_Dedupe_MergerTest extends CiviUnitTestCase { | |
8 | ||
9 | protected $_groupId; | |
10 | protected $_contactIds = array(); | |
11 | ||
3308aac0 | 12 | public function tearDown() { |
13 | $this->quickCleanup(array('civicrm_contact', 'civicrm_group_contact', 'civicrm_group')); | |
14 | parent::tearDown(); | |
15 | } | |
16 | ||
0622d221 | 17 | public function createDupeContacts() { |
18 | // create a group to hold contacts, so that dupe checks don't consider any other contacts in the DB | |
19 | $params = array( | |
20 | 'name' => 'Test Dupe Merger Group', | |
21 | 'title' => 'Test Dupe Merger Group', | |
22 | 'domain_id' => 1, | |
23 | 'is_active' => 1, | |
24 | 'visibility' => 'Public Pages', | |
0622d221 | 25 | ); |
87a56b12 | 26 | |
27 | $result = $this->callAPISuccess('group', 'create', $params); | |
0622d221 | 28 | $this->_groupId = $result['id']; |
29 | ||
30 | // contact data set | |
31 | ||
32 | // make dupe checks based on based on following contact sets: | |
33 | // FIRST - LAST - EMAIL | |
34 | // --------------------------------- | |
35 | // robin - hood - robin@example.com | |
36 | // robin - hood - robin@example.com | |
37 | // robin - hood - hood@example.com | |
38 | // robin - dale - robin@example.com | |
39 | // little - dale - dale@example.com | |
40 | // little - dale - dale@example.com | |
41 | // will - dale - dale@example.com | |
42 | // will - dale - will@example.com | |
43 | // will - dale - will@example.com | |
44 | $params = array( | |
45 | array( | |
46 | 'first_name' => 'robin', | |
47 | 'last_name' => 'hood', | |
48 | 'email' => 'robin@example.com', | |
49 | 'contact_type' => 'Individual', | |
50 | ), | |
51 | array( | |
52 | 'first_name' => 'robin', | |
53 | 'last_name' => 'hood', | |
54 | 'email' => 'robin@example.com', | |
55 | 'contact_type' => 'Individual', | |
56 | ), | |
57 | array( | |
58 | 'first_name' => 'robin', | |
59 | 'last_name' => 'hood', | |
60 | 'email' => 'hood@example.com', | |
61 | 'contact_type' => 'Individual', | |
62 | ), | |
63 | array( | |
64 | 'first_name' => 'robin', | |
65 | 'last_name' => 'dale', | |
66 | 'email' => 'robin@example.com', | |
67 | 'contact_type' => 'Individual', | |
68 | ), | |
69 | array( | |
70 | 'first_name' => 'little', | |
71 | 'last_name' => 'dale', | |
72 | 'email' => 'dale@example.com', | |
73 | 'contact_type' => 'Individual', | |
74 | ), | |
75 | array( | |
76 | 'first_name' => 'little', | |
77 | 'last_name' => 'dale', | |
78 | 'email' => 'dale@example.com', | |
79 | 'contact_type' => 'Individual', | |
80 | ), | |
81 | array( | |
82 | 'first_name' => 'will', | |
83 | 'last_name' => 'dale', | |
84 | 'email' => 'dale@example.com', | |
85 | 'contact_type' => 'Individual', | |
86 | ), | |
87 | array( | |
88 | 'first_name' => 'will', | |
89 | 'last_name' => 'dale', | |
90 | 'email' => 'will@example.com', | |
91 | 'contact_type' => 'Individual', | |
92 | ), | |
93 | array( | |
94 | 'first_name' => 'will', | |
95 | 'last_name' => 'dale', | |
96 | 'email' => 'will@example.com', | |
97 | 'contact_type' => 'Individual', | |
98 | ), | |
99 | ); | |
100 | ||
101 | $count = 1; | |
102 | foreach ($params as $param) { | |
103 | $param['version'] = 3; | |
104 | $contact = civicrm_api('contact', 'create', $param); | |
105 | $this->_contactIds[$count++] = $contact['id']; | |
106 | ||
107 | $grpParams = array( | |
108 | 'contact_id' => $contact['id'], | |
109 | 'group_id' => $this->_groupId, | |
110 | 'version' => 3, | |
111 | ); | |
87a56b12 | 112 | $this->callAPISuccess('group_contact', 'create', $grpParams); |
0622d221 | 113 | } |
114 | } | |
115 | ||
93ac19cd | 116 | /** |
117 | * Delete all created contacts. | |
118 | */ | |
0622d221 | 119 | public function deleteDupeContacts() { |
0622d221 | 120 | foreach ($this->_contactIds as $contactId) { |
93ac19cd | 121 | $this->contactDelete($contactId); |
0622d221 | 122 | } |
87a56b12 | 123 | $this->groupDelete($this->_groupId); |
0622d221 | 124 | } |
125 | ||
c8ec0753 | 126 | /** |
a354251e | 127 | * Test the batch merge. |
c8ec0753 | 128 | */ |
0622d221 | 129 | public function testBatchMergeSelectedDuplicates() { |
130 | $this->createDupeContacts(); | |
131 | ||
132 | // verify that all contacts have been created separately | |
133 | $this->assertEquals(count($this->_contactIds), 9, 'Check for number of contacts.'); | |
134 | ||
135 | $dao = new CRM_Dedupe_DAO_RuleGroup(); | |
136 | $dao->contact_type = 'Individual'; | |
137 | $dao->name = 'IndividualSupervised'; | |
138 | $dao->is_default = 1; | |
139 | $dao->find(TRUE); | |
140 | ||
141 | $foundDupes = CRM_Dedupe_Finder::dupesInGroup($dao->id, $this->_groupId); | |
142 | ||
143 | // ------------------------------------------------------------------------- | |
144 | // Name and Email (reserved) Matches ( 3 pairs ) | |
145 | // -------------------------------------------------------------------------- | |
146 | // robin - hood - robin@example.com | |
147 | // robin - hood - robin@example.com | |
148 | // little - dale - dale@example.com | |
149 | // little - dale - dale@example.com | |
150 | // will - dale - will@example.com | |
151 | // will - dale - will@example.com | |
152 | // so 3 pairs for - first + last + mail | |
153 | $this->assertEquals(count($foundDupes), 3, 'Check Individual-Supervised dupe rule for dupesInGroup().'); | |
154 | ||
155 | // Run dedupe finder as the browser would | |
39b959db SL |
156 | //avoid invalid key error |
157 | $_SERVER['REQUEST_METHOD'] = 'GET'; | |
0622d221 | 158 | $object = new CRM_Contact_Page_DedupeFind(); |
159 | $object->set('gid', $this->_groupId); | |
160 | $object->set('rgid', $dao->id); | |
161 | $object->set('action', CRM_Core_Action::UPDATE); | |
64fe2fe0 | 162 | $object->setEmbedded(TRUE); |
0622d221 | 163 | @$object->run(); |
164 | ||
165 | // Retrieve pairs from prev next cache table | |
166 | $select = array('pn.is_selected' => 'is_selected'); | |
b1679439 | 167 | $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($dao->id, $this->_groupId); |
0622d221 | 168 | $pnDupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, NULL, NULL, 0, 0, $select); |
169 | ||
170 | $this->assertEquals(count($foundDupes), count($pnDupePairs), 'Check number of dupe pairs in prev next cache.'); | |
171 | ||
172 | // mark first two pairs as selected | |
173 | CRM_Core_DAO::singleValueQuery("UPDATE civicrm_prevnext_cache SET is_selected = 1 WHERE id IN ({$pnDupePairs[0]['prevnext_id']}, {$pnDupePairs[1]['prevnext_id']})"); | |
174 | ||
175 | $pnDupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, NULL, NULL, 0, 0, $select); | |
176 | $this->assertEquals($pnDupePairs[0]['is_selected'], 1, 'Check if first record in dupe pairs is marked as selected.'); | |
177 | $this->assertEquals($pnDupePairs[0]['is_selected'], 1, 'Check if second record in dupe pairs is marked as selected.'); | |
178 | ||
179 | // batch merge selected dupes | |
d13a105a | 180 | $result = CRM_Dedupe_Merger::batchMerge($dao->id, $this->_groupId, 'safe', 5, 1); |
0622d221 | 181 | $this->assertEquals(count($result['merged']), 2, 'Check number of merged pairs.'); |
182 | ||
183 | // retrieve pairs from prev next cache table | |
184 | $pnDupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, NULL, NULL, 0, 0, $select); | |
185 | $this->assertEquals(count($pnDupePairs), 1, 'Check number of remaining dupe pairs in prev next cache.'); | |
186 | ||
187 | $this->deleteDupeContacts(); | |
188 | } | |
189 | ||
c8ec0753 | 190 | /** |
a354251e | 191 | * Test the batch merge. |
c8ec0753 | 192 | */ |
0622d221 | 193 | public function testBatchMergeAllDuplicates() { |
194 | $this->createDupeContacts(); | |
195 | ||
196 | // verify that all contacts have been created separately | |
197 | $this->assertEquals(count($this->_contactIds), 9, 'Check for number of contacts.'); | |
198 | ||
199 | $dao = new CRM_Dedupe_DAO_RuleGroup(); | |
200 | $dao->contact_type = 'Individual'; | |
201 | $dao->name = 'IndividualSupervised'; | |
202 | $dao->is_default = 1; | |
203 | $dao->find(TRUE); | |
204 | ||
205 | $foundDupes = CRM_Dedupe_Finder::dupesInGroup($dao->id, $this->_groupId); | |
206 | ||
207 | // ------------------------------------------------------------------------- | |
208 | // Name and Email (reserved) Matches ( 3 pairs ) | |
209 | // -------------------------------------------------------------------------- | |
210 | // robin - hood - robin@example.com | |
211 | // robin - hood - robin@example.com | |
212 | // little - dale - dale@example.com | |
213 | // little - dale - dale@example.com | |
214 | // will - dale - will@example.com | |
215 | // will - dale - will@example.com | |
216 | // so 3 pairs for - first + last + mail | |
217 | $this->assertEquals(count($foundDupes), 3, 'Check Individual-Supervised dupe rule for dupesInGroup().'); | |
218 | ||
219 | // Run dedupe finder as the browser would | |
39b959db SL |
220 | //avoid invalid key error |
221 | $_SERVER['REQUEST_METHOD'] = 'GET'; | |
0622d221 | 222 | $object = new CRM_Contact_Page_DedupeFind(); |
223 | $object->set('gid', $this->_groupId); | |
224 | $object->set('rgid', $dao->id); | |
225 | $object->set('action', CRM_Core_Action::UPDATE); | |
64fe2fe0 | 226 | $object->setEmbedded(TRUE); |
0622d221 | 227 | @$object->run(); |
228 | ||
229 | // Retrieve pairs from prev next cache table | |
230 | $select = array('pn.is_selected' => 'is_selected'); | |
b1679439 | 231 | $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($dao->id, $this->_groupId); |
0622d221 | 232 | $pnDupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, NULL, NULL, 0, 0, $select); |
233 | ||
234 | $this->assertEquals(count($foundDupes), count($pnDupePairs), 'Check number of dupe pairs in prev next cache.'); | |
235 | ||
236 | // batch merge all dupes | |
d13a105a | 237 | $result = CRM_Dedupe_Merger::batchMerge($dao->id, $this->_groupId, 'safe', 5, 2); |
0622d221 | 238 | $this->assertEquals(count($result['merged']), 3, 'Check number of merged pairs.'); |
239 | ||
240 | // retrieve pairs from prev next cache table | |
241 | $pnDupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, NULL, NULL, 0, 0, $select); | |
242 | $this->assertEquals(count($pnDupePairs), 0, 'Check number of remaining dupe pairs in prev next cache.'); | |
243 | ||
244 | $this->deleteDupeContacts(); | |
245 | } | |
246 | ||
bf17fa88 | 247 | /** |
248 | * The goal of this function is to test that all required tables are returned. | |
249 | */ | |
250 | public function testGetCidRefs() { | |
251 | $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, 'Contacts'); | |
252 | $this->assertEquals(array_merge($this->getStaticCIDRefs(), $this->getHackedInCIDRef()), CRM_Dedupe_Merger::cidRefs()); | |
253 | $this->assertEquals(array_merge($this->getCalculatedCIDRefs(), $this->getHackedInCIDRef()), CRM_Dedupe_Merger::cidRefs()); | |
254 | } | |
255 | ||
256 | /** | |
257 | * Get the list of not-really-cid-refs that are currently hacked in. | |
258 | * | |
259 | * This is hacked into getCIDs function. | |
260 | * | |
261 | * @return array | |
262 | */ | |
263 | public function getHackedInCIDRef() { | |
264 | return array( | |
265 | 'civicrm_entity_tag' => array( | |
266 | 0 => 'entity_id', | |
267 | ), | |
268 | ); | |
269 | } | |
270 | ||
2988f5c7 | 271 | /** |
272 | * Test function that gets duplicate pairs. | |
273 | * | |
274 | * It turns out there are 2 code paths retrieving this data so my initial focus is on ensuring | |
275 | * they match. | |
276 | */ | |
277 | public function testGetMatches() { | |
278 | $this->setupMatchData(); | |
279 | $pairs = CRM_Dedupe_Merger::getDuplicatePairs( | |
280 | 1, | |
281 | NULL, | |
282 | TRUE, | |
283 | 25, | |
284 | FALSE | |
285 | ); | |
286 | ||
287 | $this->assertEquals(array( | |
288 | 0 => array( | |
08cde01f | 289 | 'srcID' => $this->contacts[1]['id'], |
2988f5c7 | 290 | 'srcName' => 'Mr. Mickey Mouse II', |
08cde01f | 291 | 'dstID' => $this->contacts[0]['id'], |
2988f5c7 | 292 | 'dstName' => 'Mr. Mickey Mouse II', |
293 | 'weight' => 20, | |
294 | 'canMerge' => TRUE, | |
295 | ), | |
3308aac0 | 296 | 1 => array( |
08cde01f | 297 | 'srcID' => $this->contacts[3]['id'], |
3308aac0 | 298 | 'srcName' => 'Mr. Minnie Mouse II', |
08cde01f | 299 | 'dstID' => $this->contacts[2]['id'], |
3308aac0 | 300 | 'dstName' => 'Mr. Minnie Mouse II', |
301 | 'weight' => 20, | |
302 | 'canMerge' => TRUE, | |
303 | ), | |
2988f5c7 | 304 | ), $pairs); |
305 | } | |
306 | ||
bc0f3965 | 307 | /** |
308 | * Test function that gets organization pairs. | |
309 | * | |
310 | * Note the rule will match on organization_name OR email - hence lots of matches. | |
311 | */ | |
312 | public function testGetOrganizationMatches() { | |
313 | $this->setupMatchData(); | |
314 | $ruleGroups = $this->callAPISuccessGetSingle('RuleGroup', array('contact_type' => 'Organization', 'used' => 'Supervised')); | |
315 | ||
316 | $pairs = CRM_Dedupe_Merger::getDuplicatePairs( | |
317 | $ruleGroups['id'], | |
318 | NULL, | |
319 | TRUE, | |
320 | 25, | |
321 | FALSE | |
322 | ); | |
323 | ||
72475b30 | 324 | $expectedPairs = array( |
bc0f3965 | 325 | 0 => array( |
326 | 'srcID' => $this->contacts[5]['id'], | |
327 | 'srcName' => 'Walt Disney Ltd', | |
328 | 'dstID' => $this->contacts[4]['id'], | |
329 | 'dstName' => 'Walt Disney Ltd', | |
330 | 'weight' => 20, | |
331 | 'canMerge' => TRUE, | |
332 | ), | |
333 | 1 => array( | |
334 | 'srcID' => $this->contacts[7]['id'], | |
335 | 'srcName' => 'Walt Disney', | |
336 | 'dstID' => $this->contacts[6]['id'], | |
337 | 'dstName' => 'Walt Disney', | |
338 | 'weight' => 10, | |
339 | 'canMerge' => TRUE, | |
340 | ), | |
341 | 2 => array( | |
342 | 'srcID' => $this->contacts[6]['id'], | |
343 | 'srcName' => 'Walt Disney', | |
344 | 'dstID' => $this->contacts[4]['id'], | |
345 | 'dstName' => 'Walt Disney Ltd', | |
346 | 'weight' => 10, | |
347 | 'canMerge' => TRUE, | |
348 | ), | |
349 | 3 => array( | |
350 | 'srcID' => $this->contacts[6]['id'], | |
351 | 'srcName' => 'Walt Disney', | |
352 | 'dstID' => $this->contacts[5]['id'], | |
353 | 'dstName' => 'Walt Disney Ltd', | |
354 | 'weight' => 10, | |
355 | 'canMerge' => TRUE, | |
356 | ), | |
72475b30 TO |
357 | ); |
358 | usort($pairs, array(__CLASS__, 'compareDupes')); | |
359 | usort($expectedPairs, array(__CLASS__, 'compareDupes')); | |
360 | $this->assertEquals($expectedPairs, $pairs); | |
361 | } | |
362 | ||
363 | /** | |
364 | * Function to sort $duplicate records in a stable way. | |
365 | * | |
366 | * @param array $a | |
367 | * @param array $b | |
368 | * @return int | |
369 | */ | |
370 | public static function compareDupes($a, $b) { | |
371 | foreach (array('srcName', 'dstName', 'srcID', 'dstID') as $field) { | |
372 | if ($a[$field] != $b[$field]) { | |
373 | return ($a[$field] < $b[$field]) ? 1 : -1; | |
374 | } | |
375 | } | |
376 | return 0; | |
bc0f3965 | 377 | } |
378 | ||
379 | /** | |
380 | * Test function that gets organization duplicate pairs. | |
381 | */ | |
382 | public function testGetOrganizationMatchesInGroup() { | |
383 | $this->setupMatchData(); | |
384 | $ruleGroups = $this->callAPISuccessGetSingle('RuleGroup', array('contact_type' => 'Organization', 'used' => 'Supervised')); | |
385 | ||
386 | $groupID = $this->groupCreate(array('title' => 'she-mice')); | |
387 | ||
388 | $this->callAPISuccess('GroupContact', 'create', array('group_id' => $groupID, 'contact_id' => $this->contacts[4]['id'])); | |
389 | ||
390 | $pairs = CRM_Dedupe_Merger::getDuplicatePairs( | |
391 | $ruleGroups['id'], | |
392 | $groupID, | |
393 | TRUE, | |
394 | 25, | |
395 | FALSE | |
396 | ); | |
397 | ||
398 | $this->assertEquals(array( | |
399 | 0 => array( | |
400 | 'srcID' => $this->contacts[5]['id'], | |
401 | 'srcName' => 'Walt Disney Ltd', | |
402 | 'dstID' => $this->contacts[4]['id'], | |
403 | 'dstName' => 'Walt Disney Ltd', | |
404 | 'weight' => 20, | |
405 | 'canMerge' => TRUE, | |
406 | ), | |
407 | 1 => array( | |
408 | 'srcID' => $this->contacts[6]['id'], | |
409 | 'srcName' => 'Walt Disney', | |
410 | 'dstID' => $this->contacts[4]['id'], | |
411 | 'dstName' => 'Walt Disney Ltd', | |
412 | 'weight' => 10, | |
413 | 'canMerge' => TRUE, | |
414 | ), | |
415 | ), $pairs); | |
be61083d | 416 | |
417 | $this->callAPISuccess('GroupContact', 'create', array('group_id' => $groupID, 'contact_id' => $this->contacts[5]['id'])); | |
418 | CRM_Core_DAO::executeQuery("DELETE FROM civicrm_prevnext_cache"); | |
419 | $pairs = CRM_Dedupe_Merger::getDuplicatePairs( | |
420 | $ruleGroups['id'], | |
421 | $groupID, | |
422 | TRUE, | |
423 | 25, | |
424 | FALSE | |
425 | ); | |
426 | ||
427 | $this->assertEquals(array( | |
428 | 0 => array( | |
429 | 'srcID' => $this->contacts[5]['id'], | |
430 | 'srcName' => 'Walt Disney Ltd', | |
431 | 'dstID' => $this->contacts[4]['id'], | |
432 | 'dstName' => 'Walt Disney Ltd', | |
433 | 'weight' => 20, | |
434 | 'canMerge' => TRUE, | |
435 | ), | |
436 | 1 => array( | |
437 | 'srcID' => $this->contacts[6]['id'], | |
438 | 'srcName' => 'Walt Disney', | |
439 | 'dstID' => $this->contacts[4]['id'], | |
440 | 'dstName' => 'Walt Disney Ltd', | |
441 | 'weight' => 10, | |
442 | 'canMerge' => TRUE, | |
443 | ), | |
444 | 2 => array( | |
445 | 'srcID' => $this->contacts[6]['id'], | |
446 | 'srcName' => 'Walt Disney', | |
447 | 'dstID' => $this->contacts[5]['id'], | |
448 | 'dstName' => 'Walt Disney Ltd', | |
449 | 'weight' => 10, | |
450 | 'canMerge' => TRUE, | |
451 | ), | |
452 | ), $pairs); | |
bc0f3965 | 453 | } |
454 | ||
3308aac0 | 455 | /** |
456 | * Test function that gets duplicate pairs. | |
457 | * | |
458 | * It turns out there are 2 code paths retrieving this data so my initial focus is on ensuring | |
459 | * they match. | |
460 | */ | |
461 | public function testGetMatchesInGroup() { | |
462 | $this->setupMatchData(); | |
463 | ||
464 | $groupID = $this->groupCreate(array('title' => 'she-mice')); | |
465 | ||
466 | $this->callAPISuccess('GroupContact', 'create', array('group_id' => $groupID, 'contact_id' => $this->contacts[3]['id'])); | |
467 | ||
468 | $pairs = CRM_Dedupe_Merger::getDuplicatePairs( | |
469 | 1, | |
470 | $groupID, | |
471 | TRUE, | |
472 | 25, | |
473 | FALSE | |
474 | ); | |
475 | ||
476 | $this->assertEquals(array( | |
477 | 0 => array( | |
478 | 'srcID' => $this->contacts[3]['id'], | |
479 | 'srcName' => 'Mr. Minnie Mouse II', | |
480 | 'dstID' => $this->contacts[2]['id'], | |
481 | 'dstName' => 'Mr. Minnie Mouse II', | |
482 | 'weight' => 20, | |
483 | 'canMerge' => TRUE, | |
484 | ), | |
485 | ), $pairs); | |
486 | } | |
487 | ||
c231c0dd JP |
488 | /** |
489 | * Test migration of Membership. | |
490 | */ | |
491 | public function testMergeMembership() { | |
492 | // Contacts setup | |
493 | $this->setupMatchData(); | |
494 | $originalContactID = $this->contacts[0]['id']; | |
495 | $duplicateContactID = $this->contacts[1]['id']; | |
496 | ||
497 | //Add Membership for the duplicate contact. | |
498 | $memTypeId = $this->membershipTypeCreate(); | |
499 | $membership = $this->callAPISuccess('Membership', 'create', [ | |
500 | 'membership_type_id' => $memTypeId, | |
501 | 'contact_id' => $duplicateContactID, | |
502 | ]); | |
503 | //Assert if 'add new' checkbox is enabled on the merge form. | |
504 | $rowsElementsAndInfo = CRM_Dedupe_Merger::getRowsElementsAndInfo($originalContactID, $duplicateContactID); | |
505 | foreach ($rowsElementsAndInfo['elements'] as $element) { | |
506 | if (!empty($element[3]) && $element[3] == 'add new') { | |
507 | $checkedAttr = ['checked' => 'checked']; | |
508 | $this->checkArrayEquals($element[4], $checkedAttr); | |
509 | } | |
510 | } | |
511 | ||
512 | //Merge and move the mem to the main contact. | |
513 | $this->mergeContacts($originalContactID, $duplicateContactID, [ | |
514 | 'move_rel_table_memberships' => 1, | |
39b959db | 515 | 'operation' => ['move_rel_table_memberships' => ['add' => 1]], |
c231c0dd JP |
516 | ]); |
517 | ||
518 | //Check if membership is correctly transferred to original contact. | |
519 | $originalContactMembership = $this->callAPISuccess('Membership', 'get', [ | |
520 | 'membership_type_id' => $memTypeId, | |
521 | 'contact_id' => $originalContactID, | |
522 | ]); | |
523 | $this->assertEquals(1, $originalContactMembership['count']); | |
524 | } | |
525 | ||
0946ab3f | 526 | /** |
527 | * CRM-19653 : Test that custom field data should/shouldn't be overriden on | |
528 | * selecting/not selecting option to migrate data respectively | |
529 | */ | |
530 | public function testCustomDataOverwrite() { | |
dba77ae8 CR |
531 | // Create Custom Field |
532 | $createGroup = $this->setupCustomGroupForIndividual(); | |
533 | $createField = $this->setupCustomField('Graduation', $createGroup); | |
534 | $customFieldName = "custom_" . $createField['id']; | |
535 | ||
536 | // Contacts setup | |
0946ab3f | 537 | $this->setupMatchData(); |
538 | ||
539 | $originalContactID = $this->contacts[0]['id']; | |
39b959db SL |
540 | // used as duplicate contact in 1st use-case |
541 | $duplicateContactID1 = $this->contacts[1]['id']; | |
542 | // used as duplicate contact in 2nd use-case | |
543 | $duplicateContactID2 = $this->contacts[2]['id']; | |
0946ab3f | 544 | |
0946ab3f | 545 | // update the text custom field for original contact with value 'abc' |
546 | $this->callAPISuccess('Contact', 'create', array( | |
547 | 'id' => $originalContactID, | |
dba77ae8 | 548 | "{$customFieldName}" => 'abc', |
0946ab3f | 549 | )); |
dba77ae8 CR |
550 | $this->assertCustomFieldValue($originalContactID, 'abc', $customFieldName); |
551 | ||
0946ab3f | 552 | // update the text custom field for duplicate contact 1 with value 'def' |
553 | $this->callAPISuccess('Contact', 'create', array( | |
554 | 'id' => $duplicateContactID1, | |
dba77ae8 | 555 | "{$customFieldName}" => 'def', |
0946ab3f | 556 | )); |
dba77ae8 CR |
557 | $this->assertCustomFieldValue($duplicateContactID1, 'def', $customFieldName); |
558 | ||
0946ab3f | 559 | // update the text custom field for duplicate contact 2 with value 'ghi' |
560 | $this->callAPISuccess('Contact', 'create', array( | |
561 | 'id' => $duplicateContactID2, | |
dba77ae8 | 562 | "{$customFieldName}" => 'ghi', |
0946ab3f | 563 | )); |
dba77ae8 | 564 | $this->assertCustomFieldValue($duplicateContactID2, 'ghi', $customFieldName); |
0946ab3f | 565 | |
566 | /*** USE-CASE 1: DO NOT OVERWRITE CUSTOM FIELD VALUE **/ | |
dba77ae8 | 567 | $this->mergeContacts($originalContactID, $duplicateContactID1, array( |
39b959db | 568 | "move_{$customFieldName}" => NULL, |
0946ab3f | 569 | )); |
dba77ae8 | 570 | $this->assertCustomFieldValue($originalContactID, 'abc', $customFieldName); |
0946ab3f | 571 | |
572 | /*** USE-CASE 2: OVERWRITE CUSTOM FIELD VALUE **/ | |
dba77ae8 CR |
573 | $this->mergeContacts($originalContactID, $duplicateContactID2, array( |
574 | "move_{$customFieldName}" => 'ghi', | |
575 | )); | |
576 | $this->assertCustomFieldValue($originalContactID, 'ghi', $customFieldName); | |
577 | ||
578 | // cleanup created custom set | |
579 | $this->callAPISuccess('CustomField', 'delete', array('id' => $createField['id'])); | |
580 | $this->callAPISuccess('CustomGroup', 'delete', array('id' => $createGroup['id'])); | |
581 | } | |
582 | ||
583 | /** | |
584 | * Verifies that when a contact with a custom field value is merged into a | |
585 | * contact without a record int its corresponding custom group table, and none | |
586 | * of the custom fields of that custom table are selected, the value is not | |
587 | * merged in. | |
588 | */ | |
589 | public function testMigrationOfUnselectedCustomDataOnEmptyCustomRecord() { | |
590 | // Create Custom Fields | |
591 | $createGroup = $this->setupCustomGroupForIndividual(); | |
592 | $customField1 = $this->setupCustomField('TestField', $createGroup); | |
593 | ||
c1955865 J |
594 | // Create multi-value custom field |
595 | $multiGroup = $this->CustomGroupMultipleCreateByParams(); | |
596 | $multiField = $this->customFieldCreate(array( | |
597 | 'custom_group_id' => $multiGroup['id'], | |
598 | 'label' => 'field_1' . $multiGroup['id'], | |
599 | 'in_selector' => 1, | |
600 | )); | |
601 | ||
dba77ae8 CR |
602 | // Contacts setup |
603 | $this->setupMatchData(); | |
604 | $originalContactID = $this->contacts[0]['id']; | |
605 | $duplicateContactID = $this->contacts[1]['id']; | |
606 | ||
607 | // Update the text custom fields for duplicate contact | |
608 | $this->callAPISuccess('Contact', 'create', array( | |
609 | 'id' => $duplicateContactID, | |
610 | "custom_{$customField1['id']}" => 'abc', | |
c1955865 | 611 | "custom_{$multiField['id']}" => 'def', |
dba77ae8 CR |
612 | )); |
613 | $this->assertCustomFieldValue($duplicateContactID, 'abc', "custom_{$customField1['id']}"); | |
c1955865 | 614 | $this->assertCustomFieldValue($duplicateContactID, 'def', "custom_{$multiField['id']}"); |
dba77ae8 | 615 | |
c1955865 | 616 | // Merge, and ensure that no value was migrated |
dba77ae8 | 617 | $this->mergeContacts($originalContactID, $duplicateContactID, array( |
ee3b1d86 | 618 | "move_custom_{$customField1['id']}" => NULL, |
c1955865 | 619 | "move_rel_table_custom_{$multiGroup['id']}" => NULL, |
dba77ae8 CR |
620 | )); |
621 | $this->assertCustomFieldValue($originalContactID, '', "custom_{$customField1['id']}"); | |
c1955865 | 622 | $this->assertCustomFieldValue($originalContactID, '', "custom_{$multiField['id']}"); |
dba77ae8 CR |
623 | |
624 | // cleanup created custom set | |
625 | $this->callAPISuccess('CustomField', 'delete', array('id' => $customField1['id'])); | |
626 | $this->callAPISuccess('CustomGroup', 'delete', array('id' => $createGroup['id'])); | |
c1955865 J |
627 | $this->callAPISuccess('CustomField', 'delete', array('id' => $multiField['id'])); |
628 | $this->callAPISuccess('CustomGroup', 'delete', array('id' => $multiGroup['id'])); | |
dba77ae8 CR |
629 | } |
630 | ||
631 | /** | |
632 | * Tests that if only part of the custom fields of a custom group are selected | |
633 | * for a merge, only those values are merged, while all other fields of the | |
634 | * custom group retain their original value, specifically for a contact with | |
635 | * no records on the custom group table. | |
636 | */ | |
637 | public function testMigrationOfSomeCustomDataOnEmptyCustomRecord() { | |
638 | // Create Custom Fields | |
639 | $createGroup = $this->setupCustomGroupForIndividual(); | |
640 | $customField1 = $this->setupCustomField('Test1', $createGroup); | |
641 | $customField2 = $this->setupCustomField('Test2', $createGroup); | |
642 | ||
c1955865 J |
643 | // Create multi-value custom field |
644 | $multiGroup = $this->CustomGroupMultipleCreateByParams(); | |
645 | $multiField = $this->customFieldCreate(array( | |
646 | 'custom_group_id' => $multiGroup['id'], | |
647 | 'label' => 'field_1' . $multiGroup['id'], | |
648 | 'in_selector' => 1, | |
649 | )); | |
650 | ||
dba77ae8 CR |
651 | // Contacts setup |
652 | $this->setupMatchData(); | |
653 | $originalContactID = $this->contacts[0]['id']; | |
654 | $duplicateContactID = $this->contacts[1]['id']; | |
655 | ||
656 | // Update the text custom fields for duplicate contact | |
657 | $this->callAPISuccess('Contact', 'create', array( | |
658 | 'id' => $duplicateContactID, | |
659 | "custom_{$customField1['id']}" => 'abc', | |
660 | "custom_{$customField2['id']}" => 'def', | |
c1955865 | 661 | "custom_{$multiField['id']}" => 'ghi', |
dba77ae8 CR |
662 | )); |
663 | $this->assertCustomFieldValue($duplicateContactID, 'abc', "custom_{$customField1['id']}"); | |
664 | $this->assertCustomFieldValue($duplicateContactID, 'def', "custom_{$customField2['id']}"); | |
c1955865 | 665 | $this->assertCustomFieldValue($duplicateContactID, 'ghi', "custom_{$multiField['id']}"); |
dba77ae8 CR |
666 | |
667 | // Perform merge | |
668 | $this->mergeContacts($originalContactID, $duplicateContactID, array( | |
ee3b1d86 | 669 | "move_custom_{$customField1['id']}" => NULL, |
dba77ae8 | 670 | "move_custom_{$customField2['id']}" => 'def', |
c1955865 | 671 | "move_rel_table_custom_{$multiGroup['id']}" => '1', |
dba77ae8 CR |
672 | )); |
673 | $this->assertCustomFieldValue($originalContactID, '', "custom_{$customField1['id']}"); | |
674 | $this->assertCustomFieldValue($originalContactID, 'def', "custom_{$customField2['id']}"); | |
c1955865 | 675 | $this->assertCustomFieldValue($originalContactID, 'ghi', "custom_{$multiField['id']}"); |
dba77ae8 CR |
676 | |
677 | // cleanup created custom set | |
678 | $this->callAPISuccess('CustomField', 'delete', array('id' => $customField1['id'])); | |
679 | $this->callAPISuccess('CustomField', 'delete', array('id' => $customField2['id'])); | |
680 | $this->callAPISuccess('CustomGroup', 'delete', array('id' => $createGroup['id'])); | |
c1955865 J |
681 | $this->callAPISuccess('CustomField', 'delete', array('id' => $multiField['id'])); |
682 | $this->callAPISuccess('CustomGroup', 'delete', array('id' => $multiGroup['id'])); | |
dba77ae8 CR |
683 | } |
684 | ||
685 | /** | |
686 | * Calls merge method on given contacts, with values given in $params array. | |
687 | * | |
688 | * @param $originalContactID | |
689 | * ID of target contact | |
690 | * @param $duplicateContactID | |
691 | * ID of contact to be merged | |
692 | * @param $params | |
693 | * Array of fields to be merged from source into target contact, of the form | |
694 | * ['move_<fieldName>' => <fieldValue>] | |
695 | */ | |
696 | private function mergeContacts($originalContactID, $duplicateContactID, $params) { | |
697 | $rowsElementsAndInfo = CRM_Dedupe_Merger::getRowsElementsAndInfo($originalContactID, $duplicateContactID); | |
698 | ||
0946ab3f | 699 | $migrationData = array( |
700 | 'main_details' => $rowsElementsAndInfo['main_details'], | |
701 | 'other_details' => $rowsElementsAndInfo['other_details'], | |
0946ab3f | 702 | ); |
dba77ae8 CR |
703 | |
704 | // Migrate data of duplicate contact | |
705 | CRM_Dedupe_Merger::moveAllBelongings($originalContactID, $duplicateContactID, array_merge($migrationData, $params)); | |
706 | } | |
707 | ||
708 | /** | |
709 | * Checks if the expected value for the given field corresponds to what is | |
710 | * stored in the database for the given contact ID. | |
711 | * | |
712 | * @param $contactID | |
713 | * @param $expectedValue | |
714 | * @param $customFieldName | |
715 | */ | |
716 | private function assertCustomFieldValue($contactID, $expectedValue, $customFieldName) { | |
0946ab3f | 717 | $data = $this->callAPISuccess('Contact', 'getsingle', array( |
dba77ae8 | 718 | 'id' => $contactID, |
0946ab3f | 719 | 'return' => array($customFieldName), |
720 | )); | |
0946ab3f | 721 | |
dba77ae8 CR |
722 | $this->assertEquals($expectedValue, $data[$customFieldName], "Custom field value was supposed to be '{$expectedValue}', '{$data[$customFieldName]}' found."); |
723 | } | |
724 | ||
725 | /** | |
726 | * Creates a custom group to run tests on contacts that are individuals. | |
727 | * | |
728 | * @return array | |
729 | * Data for the created custom group record | |
730 | */ | |
731 | private function setupCustomGroupForIndividual() { | |
732 | $customGroup = $this->callAPISuccess('custom_group', 'get', array( | |
733 | 'name' => 'test_group', | |
734 | )); | |
735 | ||
736 | if ($customGroup['count'] > 0) { | |
737 | $this->callAPISuccess('CustomGroup', 'delete', array('id' => $customGroup['id'])); | |
738 | } | |
739 | ||
740 | $customGroup = $this->callAPISuccess('custom_group', 'create', array( | |
741 | 'title' => 'Test_Group', | |
742 | 'name' => 'test_group', | |
743 | 'extends' => array('Individual'), | |
744 | 'style' => 'Inline', | |
745 | 'is_multiple' => FALSE, | |
746 | 'is_active' => 1, | |
747 | )); | |
748 | ||
749 | return $customGroup; | |
750 | } | |
751 | ||
752 | /** | |
753 | * Creates a custom field on the provided custom group with the given field | |
754 | * label. | |
755 | * | |
756 | * @param $fieldLabel | |
757 | * @param $createGroup | |
758 | * | |
759 | * @return array | |
760 | * Data for the created custom field record | |
761 | */ | |
762 | private function setupCustomField($fieldLabel, $createGroup) { | |
763 | return $this->callAPISuccess('custom_field', 'create', array( | |
764 | 'label' => $fieldLabel, | |
765 | 'data_type' => 'Alphanumeric', | |
766 | 'html_type' => 'Text', | |
767 | 'custom_group_id' => $createGroup['id'], | |
768 | )); | |
0946ab3f | 769 | } |
770 | ||
3308aac0 | 771 | /** |
772 | * Set up some contacts for our matching. | |
773 | */ | |
2988f5c7 | 774 | public function setupMatchData() { |
775 | $fixtures = array( | |
776 | array( | |
777 | 'first_name' => 'Mickey', | |
778 | 'last_name' => 'Mouse', | |
779 | 'email' => 'mickey@mouse.com', | |
780 | ), | |
781 | array( | |
782 | 'first_name' => 'Mickey', | |
783 | 'last_name' => 'Mouse', | |
784 | 'email' => 'mickey@mouse.com', | |
785 | ), | |
786 | array( | |
787 | 'first_name' => 'Minnie', | |
788 | 'last_name' => 'Mouse', | |
789 | 'email' => 'mickey@mouse.com', | |
790 | ), | |
3308aac0 | 791 | array( |
792 | 'first_name' => 'Minnie', | |
793 | 'last_name' => 'Mouse', | |
794 | 'email' => 'mickey@mouse.com', | |
795 | ), | |
2988f5c7 | 796 | ); |
797 | foreach ($fixtures as $fixture) { | |
798 | $contactID = $this->individualCreate($fixture); | |
799 | $this->contacts[] = array_merge($fixture, array('id' => $contactID)); | |
bc0f3965 | 800 | } |
801 | $organizationFixtures = array( | |
802 | array( | |
803 | 'organization_name' => 'Walt Disney Ltd', | |
804 | 'email' => 'walt@disney.com', | |
805 | ), | |
806 | array( | |
807 | 'organization_name' => 'Walt Disney Ltd', | |
808 | 'email' => 'walt@disney.com', | |
809 | ), | |
810 | array( | |
811 | 'organization_name' => 'Walt Disney', | |
812 | 'email' => 'walt@disney.com', | |
813 | ), | |
814 | array( | |
815 | 'organization_name' => 'Walt Disney', | |
816 | 'email' => 'walter@disney.com', | |
817 | ), | |
818 | ); | |
819 | foreach ($organizationFixtures as $fixture) { | |
820 | $contactID = $this->organizationCreate($fixture); | |
821 | $this->contacts[] = array_merge($fixture, array('id' => $contactID)); | |
2988f5c7 | 822 | } |
823 | } | |
824 | ||
bf17fa88 | 825 | /** |
826 | * Get the list of tables that refer to the CID. | |
827 | * | |
828 | * This is a statically maintained (in this test list). | |
829 | * | |
830 | * There is also a check against an automated list but having both seems to add extra stability to me. They do | |
831 | * not change often. | |
832 | */ | |
833 | public function getStaticCIDRefs() { | |
834 | return array( | |
835 | 'civicrm_acl_cache' => array( | |
836 | 0 => 'contact_id', | |
837 | ), | |
838 | 'civicrm_acl_contact_cache' => array( | |
dbb4e4f9 | 839 | 0 => 'contact_id', |
bf17fa88 | 840 | ), |
841 | 'civicrm_action_log' => array( | |
842 | 0 => 'contact_id', | |
843 | ), | |
844 | 'civicrm_activity_contact' => array( | |
845 | 0 => 'contact_id', | |
846 | ), | |
847 | 'civicrm_address' => array( | |
848 | 0 => 'contact_id', | |
849 | ), | |
850 | 'civicrm_batch' => array( | |
851 | 0 => 'created_id', | |
852 | 1 => 'modified_id', | |
853 | ), | |
854 | 'civicrm_campaign' => array( | |
855 | 0 => 'created_id', | |
856 | 1 => 'last_modified_id', | |
857 | ), | |
858 | 'civicrm_case_contact' => array( | |
859 | 0 => 'contact_id', | |
860 | ), | |
861 | 'civicrm_contact' => array( | |
862 | 0 => 'primary_contact_id', | |
863 | 1 => 'employer_id', | |
864 | ), | |
865 | 'civicrm_contribution' => array( | |
866 | 0 => 'contact_id', | |
867 | ), | |
868 | 'civicrm_contribution_page' => array( | |
869 | 0 => 'created_id', | |
870 | ), | |
871 | 'civicrm_contribution_recur' => array( | |
872 | 0 => 'contact_id', | |
873 | ), | |
874 | 'civicrm_contribution_soft' => array( | |
875 | 0 => 'contact_id', | |
876 | ), | |
877 | 'civicrm_custom_group' => array( | |
878 | 0 => 'created_id', | |
879 | ), | |
880 | 'civicrm_dashboard_contact' => array( | |
881 | 0 => 'contact_id', | |
882 | ), | |
883 | 'civicrm_dedupe_exception' => array( | |
884 | 0 => 'contact_id1', | |
885 | 1 => 'contact_id2', | |
886 | ), | |
887 | 'civicrm_domain' => array( | |
888 | 0 => 'contact_id', | |
889 | ), | |
890 | 'civicrm_email' => array( | |
891 | 0 => 'contact_id', | |
892 | ), | |
893 | 'civicrm_event' => array( | |
894 | 0 => 'created_id', | |
895 | ), | |
896 | 'civicrm_event_carts' => array( | |
897 | 0 => 'user_id', | |
898 | ), | |
899 | 'civicrm_financial_account' => array( | |
900 | 0 => 'contact_id', | |
901 | ), | |
902 | 'civicrm_financial_item' => array( | |
903 | 0 => 'contact_id', | |
904 | ), | |
905 | 'civicrm_grant' => array( | |
906 | 0 => 'contact_id', | |
907 | ), | |
908 | 'civicrm_group' => array( | |
909 | 0 => 'created_id', | |
910 | 1 => 'modified_id', | |
911 | ), | |
912 | 'civicrm_group_contact' => array( | |
913 | 0 => 'contact_id', | |
914 | ), | |
915 | 'civicrm_group_contact_cache' => array( | |
916 | 0 => 'contact_id', | |
917 | ), | |
918 | 'civicrm_group_organization' => array( | |
919 | 0 => 'organization_id', | |
920 | ), | |
921 | 'civicrm_im' => array( | |
922 | 0 => 'contact_id', | |
923 | ), | |
924 | 'civicrm_log' => array( | |
925 | 0 => 'modified_id', | |
926 | ), | |
927 | 'civicrm_mailing' => array( | |
928 | 0 => 'created_id', | |
929 | 1 => 'scheduled_id', | |
930 | 2 => 'approver_id', | |
931 | ), | |
ae2c7e00 | 932 | 'civicrm_file' => array( |
933 | 'created_id', | |
934 | ), | |
bf17fa88 | 935 | 'civicrm_mailing_abtest' => array( |
936 | 0 => 'created_id', | |
937 | ), | |
938 | 'civicrm_mailing_event_queue' => array( | |
939 | 0 => 'contact_id', | |
940 | ), | |
941 | 'civicrm_mailing_event_subscribe' => array( | |
942 | 0 => 'contact_id', | |
943 | ), | |
944 | 'civicrm_mailing_recipients' => array( | |
945 | 0 => 'contact_id', | |
946 | ), | |
947 | 'civicrm_membership' => array( | |
948 | 0 => 'contact_id', | |
949 | ), | |
950 | 'civicrm_membership_log' => array( | |
951 | 0 => 'modified_id', | |
952 | ), | |
953 | 'civicrm_membership_type' => array( | |
954 | 0 => 'member_of_contact_id', | |
955 | ), | |
956 | 'civicrm_note' => array( | |
957 | 0 => 'contact_id', | |
958 | ), | |
959 | 'civicrm_openid' => array( | |
960 | 0 => 'contact_id', | |
961 | ), | |
962 | 'civicrm_participant' => array( | |
963 | 0 => 'contact_id', | |
39b959db SL |
964 | //CRM-16761 |
965 | 1 => 'transferred_to_contact_id', | |
bf17fa88 | 966 | ), |
967 | 'civicrm_payment_token' => array( | |
968 | 0 => 'contact_id', | |
969 | 1 => 'created_id', | |
970 | ), | |
971 | 'civicrm_pcp' => array( | |
972 | 0 => 'contact_id', | |
973 | ), | |
974 | 'civicrm_phone' => array( | |
975 | 0 => 'contact_id', | |
976 | ), | |
977 | 'civicrm_pledge' => array( | |
978 | 0 => 'contact_id', | |
979 | ), | |
980 | 'civicrm_print_label' => array( | |
981 | 0 => 'created_id', | |
982 | ), | |
983 | 'civicrm_relationship' => array( | |
984 | 0 => 'contact_id_a', | |
985 | 1 => 'contact_id_b', | |
986 | ), | |
987 | 'civicrm_report_instance' => array( | |
988 | 0 => 'created_id', | |
989 | 1 => 'owner_id', | |
990 | ), | |
991 | 'civicrm_setting' => array( | |
992 | 0 => 'contact_id', | |
993 | 1 => 'created_id', | |
994 | ), | |
995 | 'civicrm_subscription_history' => array( | |
996 | 0 => 'contact_id', | |
997 | ), | |
998 | 'civicrm_survey' => array( | |
999 | 0 => 'created_id', | |
1000 | 1 => 'last_modified_id', | |
1001 | ), | |
1002 | 'civicrm_tag' => array( | |
1003 | 0 => 'created_id', | |
1004 | ), | |
1005 | 'civicrm_uf_group' => array( | |
1006 | 0 => 'created_id', | |
1007 | ), | |
1008 | 'civicrm_uf_match' => array( | |
1009 | 0 => 'contact_id', | |
1010 | ), | |
1011 | 'civicrm_value_testgetcidref_1' => array( | |
1012 | 0 => 'entity_id', | |
1013 | ), | |
1014 | 'civicrm_website' => array( | |
1015 | 0 => 'contact_id', | |
1016 | ), | |
1017 | ); | |
1018 | } | |
1019 | ||
1020 | /** | |
1021 | * Get a list of CIDs that is calculated off the schema. | |
1022 | * | |
1023 | * Note this is an expensive and table locking query. Should be safe in tests though. | |
1024 | */ | |
1025 | public function getCalculatedCIDRefs() { | |
1026 | $cidRefs = array(); | |
1027 | $sql = " | |
1028 | SELECT | |
1029 | table_name, | |
1030 | column_name | |
1031 | FROM information_schema.key_column_usage | |
1032 | WHERE | |
1033 | referenced_table_schema = database() AND | |
1034 | referenced_table_name = 'civicrm_contact' AND | |
1035 | referenced_column_name = 'id'; | |
1036 | "; | |
1037 | $dao = CRM_Core_DAO::executeQuery($sql); | |
1038 | while ($dao->fetch()) { | |
1039 | $cidRefs[$dao->table_name][] = $dao->column_name; | |
1040 | } | |
1041 | // Do specific re-ordering changes to make this the same as the ref validated one. | |
1042 | // The above query orders by FK alphabetically. | |
1043 | // There might be cleverer ways to do this but it shouldn't change much. | |
1044 | $cidRefs['civicrm_contact'][0] = 'primary_contact_id'; | |
1045 | $cidRefs['civicrm_contact'][1] = 'employer_id'; | |
dbb4e4f9 | 1046 | $cidRefs['civicrm_acl_contact_cache'][0] = 'contact_id'; |
bf17fa88 | 1047 | $cidRefs['civicrm_mailing'][0] = 'created_id'; |
1048 | $cidRefs['civicrm_mailing'][1] = 'scheduled_id'; | |
1049 | $cidRefs['civicrm_mailing'][2] = 'approver_id'; | |
1050 | return $cidRefs; | |
1051 | } | |
1052 | ||
0622d221 | 1053 | } |