/** * This function deletes the activity record related to contact record. * * This is conditional on there being no target and assignee record * with other contacts. * * @param int $contactId * ContactId. * * @return true/null */ public static function cleanupActivity($contactId) { $result = NULL; if (!$contactId) { return $result; } $activityContacts = CRM_Core_OptionGroup::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name'); $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts); $transaction = new CRM_Core_Transaction(); // delete activity if there is no record in civicrm_activity_contact // pointing to any other contact record $activityContact = new CRM_Activity_DAO_ActivityContact(); $activityContact->contact_id = $contactId; $activityContact->record_type_id = $sourceID; $activityContact->find(); while ($activityContact->fetch()) { // delete activity_contact record for the deleted contact $activityContact->delete(); $activityContactOther = new CRM_Activity_DAO_ActivityContact(); $activityContactOther->activity_id = $activityContact->activity_id; // delete activity only if no other contacts connected if (!$activityContactOther->find(TRUE)) { $activityParams = array('id' => $activityContact->activity_id); $result = self::deleteActivity($activityParams); } $activityContactOther->free(); } $activityContact->free(); $transaction->commit(); return $result; }
/** * Function perform two task. * 1. Merge two duplicate contacts cases - follow CRM-5758 rules. * 2. Merge two cases of same contact - follow CRM-5598 rules. * * @param int $mainContactId contact id of main contact record. * @param int $mainCaseId case id of main case record. * @param int $otherContactId contact id of record which is going to merge. * @param int $otherCaseId case id of record which is going to merge. * * @param bool $changeClient * * @return integer|NULL * @static */ static function mergeCases($mainContactId, $mainCaseId = NULL, $otherContactId = NULL, $otherCaseId = NULL, $changeClient = FALSE) { $moveToTrash = TRUE; $duplicateContacts = FALSE; if ($mainContactId && $otherContactId && $mainContactId != $otherContactId) { $duplicateContacts = TRUE; } $duplicateCases = FALSE; if ($mainCaseId && $otherCaseId && $mainCaseId != $otherCaseId) { $duplicateCases = TRUE; } $mainCaseIds = array(); if (!$duplicateContacts && !$duplicateCases) { return $mainCaseIds; } $activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'name'); $activityStatuses = CRM_Core_PseudoConstant::activityStatus('name'); $activityContacts = CRM_Core_OptionGroup::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name'); $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts); $assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts); $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts); $processCaseIds = array($otherCaseId); if ($duplicateContacts && !$duplicateCases) { if ($changeClient) { $processCaseIds = array($mainCaseId); } else { //get all case ids for other contact. $processCaseIds = self::retrieveCaseIdsByContactId($otherContactId, TRUE); } if (!is_array($processCaseIds)) { return; } } $session = CRM_Core_Session::singleton(); $currentUserId = $session->get('userID'); CRM_Utils_Hook::pre_case_merge($mainContactId, $mainCaseId, $otherContactId, $otherCaseId, $changeClient); // copy all cases and connect to main contact id. foreach ($processCaseIds as $otherCaseId) { if ($duplicateContacts) { $mainCase = CRM_Core_DAO::copyGeneric('CRM_Case_DAO_Case', array('id' => $otherCaseId)); $mainCaseId = $mainCase->id; if (!$mainCaseId) { continue; } // CRM-11662 Copy Case custom data $extends = array('case'); $groupTree = CRM_Core_BAO_CustomGroup::getGroupDetail(NULL, NULL, $extends); if ($groupTree) { foreach ($groupTree as $groupID => $group) { $table[$groupTree[$groupID]['table_name']] = array('entity_id'); foreach ($group['fields'] as $fieldID => $field) { $table[$groupTree[$groupID]['table_name']][] = $groupTree[$groupID]['fields'][$fieldID]['column_name']; } } foreach ($table as $tableName => $tableColumns) { $insert = 'INSERT INTO ' . $tableName . ' (' . implode(', ', $tableColumns) . ') '; $tableColumns[0] = $mainCaseId; $select = 'SELECT ' . implode(', ', $tableColumns); $from = ' FROM ' . $tableName; $where = " WHERE {$tableName}.entity_id = {$otherCaseId}"; $query = $insert . $select . $from . $where; $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray); } } $mainCase->free(); $mainCaseIds[] = $mainCaseId; //insert record for case contact. $otherCaseContact = new CRM_Case_DAO_CaseContact(); $otherCaseContact->case_id = $otherCaseId; $otherCaseContact->find(); while ($otherCaseContact->fetch()) { $mainCaseContact = new CRM_Case_DAO_CaseContact(); $mainCaseContact->case_id = $mainCaseId; $mainCaseContact->contact_id = $otherCaseContact->contact_id; if ($mainCaseContact->contact_id == $otherContactId) { $mainCaseContact->contact_id = $mainContactId; } //avoid duplicate object. if (!$mainCaseContact->find(TRUE)) { $mainCaseContact->save(); } $mainCaseContact->free(); } $otherCaseContact->free(); } elseif (!$otherContactId) { $otherContactId = $mainContactId; } if (!$mainCaseId || !$otherCaseId || !$mainContactId || !$otherContactId) { continue; } // get all activities for other case. $otherCaseActivities = array(); CRM_Core_DAO::commonRetrieveAll('CRM_Case_DAO_CaseActivity', 'case_id', $otherCaseId, $otherCaseActivities); //for duplicate cases do not process singleton activities. $otherActivityIds = $singletonActivityIds = array(); foreach ($otherCaseActivities as $caseActivityId => $otherIds) { $otherActId = CRM_Utils_Array::value('activity_id', $otherIds); if (!$otherActId || in_array($otherActId, $otherActivityIds)) { continue; } $otherActivityIds[] = $otherActId; } if ($duplicateCases) { if ($openCaseType = array_search('Open Case', $activityTypes)) { $sql = "\nSELECT id\n FROM civicrm_activity\n WHERE activity_type_id = {$openCaseType}\n AND id IN ( " . implode(',', array_values($otherActivityIds)) . ');'; $dao = CRM_Core_DAO::executeQuery($sql); while ($dao->fetch()) { $singletonActivityIds[] = $dao->id; } $dao->free(); } } // migrate all activities and connect to main contact. $copiedActivityIds = $activityMappingIds = array(); sort($otherActivityIds); foreach ($otherActivityIds as $otherActivityId) { //for duplicate cases - //do not migrate singleton activities. if (!$otherActivityId || in_array($otherActivityId, $singletonActivityIds)) { continue; } //migrate activity record. $otherActivity = new CRM_Activity_DAO_Activity(); $otherActivity->id = $otherActivityId; if (!$otherActivity->find(TRUE)) { continue; } $mainActVals = array(); $mainActivity = new CRM_Activity_DAO_Activity(); CRM_Core_DAO::storeValues($otherActivity, $mainActVals); $mainActivity->copyValues($mainActVals); $mainActivity->id = NULL; $mainActivity->activity_date_time = CRM_Utils_Date::isoToMysql($otherActivity->activity_date_time); $mainActivity->source_record_id = CRM_Utils_Array::value($mainActivity->source_record_id, $activityMappingIds); $mainActivity->original_id = CRM_Utils_Array::value($mainActivity->original_id, $activityMappingIds); $mainActivity->parent_id = CRM_Utils_Array::value($mainActivity->parent_id, $activityMappingIds); $mainActivity->save(); $mainActivityId = $mainActivity->id; if (!$mainActivityId) { continue; } $activityMappingIds[$otherActivityId] = $mainActivityId; // insert log of all activities CRM_Activity_BAO_Activity::logActivityAction($mainActivity); $otherActivity->free(); $mainActivity->free(); $copiedActivityIds[] = $otherActivityId; //create case activity record. $mainCaseActivity = new CRM_Case_DAO_CaseActivity(); $mainCaseActivity->case_id = $mainCaseId; $mainCaseActivity->activity_id = $mainActivityId; $mainCaseActivity->save(); $mainCaseActivity->free(); //migrate source activity. $otherSourceActivity = new CRM_Activity_DAO_ActivityContact(); $otherSourceActivity->activity_id = $otherActivityId; $otherSourceActivity->record_type_id = $sourceID; $otherSourceActivity->find(); while ($otherSourceActivity->fetch()) { $mainActivitySource = new CRM_Activity_DAO_ActivityContact(); $mainActivitySource->record_type_id = $sourceID; $mainActivitySource->activity_id = $mainActivityId; $mainActivitySource->contact_id = $otherSourceActivity->contact_id; if ($mainActivitySource->contact_id == $otherContactId) { $mainActivitySource->contact_id = $mainContactId; } //avoid duplicate object. if (!$mainActivitySource->find(TRUE)) { $mainActivitySource->save(); } $mainActivitySource->free(); } $otherSourceActivity->free(); //migrate target activities. $otherTargetActivity = new CRM_Activity_DAO_ActivityContact(); $otherTargetActivity->activity_id = $otherActivityId; $otherTargetActivity->record_type_id = $targetID; $otherTargetActivity->find(); while ($otherTargetActivity->fetch()) { $mainActivityTarget = new CRM_Activity_DAO_ActivityContact(); $mainActivityTarget->record_type_id = $targetID; $mainActivityTarget->activity_id = $mainActivityId; $mainActivityTarget->contact_id = $otherTargetActivity->contact_id; if ($mainActivityTarget->contact_id == $otherContactId) { $mainActivityTarget->contact_id = $mainContactId; } //avoid duplicate object. if (!$mainActivityTarget->find(TRUE)) { $mainActivityTarget->save(); } $mainActivityTarget->free(); } $otherTargetActivity->free(); //migrate assignee activities. $otherAssigneeActivity = new CRM_Activity_DAO_ActivityContact(); $otherAssigneeActivity->activity_id = $otherActivityId; $otherAssigneeActivity->record_type_id = $assigneeID; $otherAssigneeActivity->find(); while ($otherAssigneeActivity->fetch()) { $mainAssigneeActivity = new CRM_Activity_DAO_ActivityContact(); $mainAssigneeActivity->activity_id = $mainActivityId; $mainAssigneeActivity->record_type_id = $assigneeID; $mainAssigneeActivity->contact_id = $otherAssigneeActivity->contact_id; if ($mainAssigneeActivity->contact_id == $otherContactId) { $mainAssigneeActivity->contact_id = $mainContactId; } //avoid duplicate object. if (!$mainAssigneeActivity->find(TRUE)) { $mainAssigneeActivity->save(); } $mainAssigneeActivity->free(); } $otherAssigneeActivity->free(); // copy custom fields and attachments $aparams = array('activityID' => $otherActivityId, 'mainActivityId' => $mainActivityId); CRM_Activity_BAO_Activity::copyExtendedActivityData($aparams); } //copy case relationship. if ($duplicateContacts) { //migrate relationship records. $otherRelationship = new CRM_Contact_DAO_Relationship(); $otherRelationship->case_id = $otherCaseId; $otherRelationship->find(); $otherRelationshipIds = array(); while ($otherRelationship->fetch()) { $otherRelVals = array(); $updateOtherRel = FALSE; CRM_Core_DAO::storeValues($otherRelationship, $otherRelVals); $mainRelationship = new CRM_Contact_DAO_Relationship(); $mainRelationship->copyValues($otherRelVals); $mainRelationship->id = NULL; $mainRelationship->case_id = $mainCaseId; if ($mainRelationship->contact_id_a == $otherContactId) { $updateOtherRel = TRUE; $mainRelationship->contact_id_a = $mainContactId; } //case creator change only when we merge user contact. if ($mainRelationship->contact_id_b == $otherContactId) { //do not change creator for change client. if (!$changeClient) { $updateOtherRel = TRUE; $mainRelationship->contact_id_b = $currentUserId ? $currentUserId : $mainContactId; } } $mainRelationship->end_date = CRM_Utils_Date::isoToMysql($otherRelationship->end_date); $mainRelationship->start_date = CRM_Utils_Date::isoToMysql($otherRelationship->start_date); //avoid duplicate object. if (!$mainRelationship->find(TRUE)) { $mainRelationship->save(); } $mainRelationship->free(); //get the other relationship ids to update end date. if ($updateOtherRel) { $otherRelationshipIds[$otherRelationship->id] = $otherRelationship->id; } } $otherRelationship->free(); //update other relationships end dates if (!empty($otherRelationshipIds)) { $sql = 'UPDATE civicrm_relationship SET end_date = CURDATE() WHERE id IN ( ' . implode(',', $otherRelationshipIds) . ')'; CRM_Core_DAO::executeQuery($sql); } } //move other case to trash. $mergeCase = self::deleteCase($otherCaseId, $moveToTrash); if (!$mergeCase) { continue; } $mergeActSubject = $mergeActSubjectDetails = $mergeActType = ''; if ($changeClient) { $mainContactDisplayName = CRM_Contact_BAO_Contact::displayName($mainContactId); $otherContactDisplayName = CRM_Contact_BAO_Contact::displayName($otherContactId); $mergeActType = array_search('Reassigned Case', $activityTypes); $mergeActSubject = ts("Case %1 reassigned client from %2 to %3. New Case ID is %4.", array(1 => $otherCaseId, 2 => $otherContactDisplayName, 3 => $mainContactDisplayName, 4 => $mainCaseId)); } elseif ($duplicateContacts) { $mergeActType = array_search('Merge Case', $activityTypes); $mergeActSubject = ts("Case %1 copied from contact id %2 to contact id %3 via merge. New Case ID is %4.", array(1 => $otherCaseId, 2 => $otherContactId, 3 => $mainContactId, 4 => $mainCaseId)); } else { $mergeActType = array_search('Merge Case', $activityTypes); $mergeActSubject = ts("Case %1 merged into case %2", array(1 => $otherCaseId, 2 => $mainCaseId)); if (!empty($copiedActivityIds)) { $sql = ' SELECT id, subject, activity_date_time, activity_type_id FROM civicrm_activity WHERE id IN (' . implode(',', $copiedActivityIds) . ')'; $dao = CRM_Core_DAO::executeQuery($sql); while ($dao->fetch()) { $mergeActSubjectDetails .= "{$dao->activity_date_time} :: {$activityTypes[$dao->activity_type_id]}"; if ($dao->subject) { $mergeActSubjectDetails .= " :: {$dao->subject}"; } $mergeActSubjectDetails .= "<br />"; } } } //create merge activity record. $activityParams = array('subject' => $mergeActSubject, 'details' => $mergeActSubjectDetails, 'status_id' => array_search('Completed', $activityStatuses), 'activity_type_id' => $mergeActType, 'source_contact_id' => $mainContactId, 'activity_date_time' => date('YmdHis')); $mergeActivity = CRM_Activity_BAO_Activity::create($activityParams); $mergeActivityId = $mergeActivity->id; if (!$mergeActivityId) { continue; } $mergeActivity->free(); //connect merge activity to case. $mergeCaseAct = array('case_id' => $mainCaseId, 'activity_id' => $mergeActivityId); self::processCaseActivity($mergeCaseAct); } CRM_Utils_Hook::post_case_merge($mainContactId, $mainCaseId, $otherContactId, $otherCaseId, $changeClient); return $mainCaseIds; }
/** * Test activity api create for case activities */ function testCaseActivityCreate() { // Create a case first $params = $this->_params; $result = $this->callAPISuccess('case', 'create', $params); $params = array('case_id' => 1, 'activity_type_id' => $this->followup_activity_type_value, 'subject' => 'Test followup', 'source_contact_id' => $this->_loggedInUser, 'target_contact_id' => $this->_params['contact_id']); $result = $this->callAPISuccess('activity', 'create', $params); $this->assertEquals($result['values'][$result['id']]['activity_type_id'], $params['activity_type_id'], 'in line ' . __LINE__); // might need this for other tests that piggyback on this one $this->_caseActivityId = $result['values'][$result['id']]['id']; // Check other DB tables populated properly - is there a better way to do this? assertDBState() requires that we know the id already. $dao = new CRM_Case_DAO_CaseActivity(); $dao->case_id = 1; $dao->activity_id = $this->_caseActivityId; $this->assertEquals($dao->find(), 1, 'case_activity table not populated correctly in line ' . __LINE__); $dao->free(); $dao = new CRM_Activity_DAO_ActivityContact(); $dao->activity_id = $this->_caseActivityId; $dao->contact_id = $this->_params['contact_id']; $dao->record_type_id = 3; $this->assertEquals($dao->find(), 1, 'activity_contact table not populated correctly in line ' . __LINE__); $dao->free(); // TODO: There's more things we could check }