diff --git a/entity/Contact_entity/recordcontainers/db/onDBDelete.js b/entity/Contact_entity/recordcontainers/db/onDBDelete.js index db41811d78df66c7f51a6c63749bdeae91f7f26f..aed5eceb442ba9c187b395da25f17467c8a8808b 100644 --- a/entity/Contact_entity/recordcontainers/db/onDBDelete.js +++ b/entity/Contact_entity/recordcontainers/db/onDBDelete.js @@ -6,7 +6,7 @@ import("system.vars"); import("DuplicateScanner_lib"); var contactId = vars.get("$field.CONTACTID"); -DuplicateScannerUtils.DeleteCachedDuplicate(contactId); +DuplicateScannerUtils.deleteCachedDuplicate(contactId); new AttributeRelationQuery(contactId, null, ContextUtils.getCurrentContextId()) .deleteAllAttributes(); diff --git a/entity/Organisation_entity/entityfields/duplicateactions/children/integratecurrentintoselectedaction/onActionProcess.js b/entity/Organisation_entity/entityfields/duplicateactions/children/integratecurrentintoselectedaction/onActionProcess.js index 5b61fa56b4a367c5d2c80f2d90aa249fa2033b11..d75b5308bf2fc6e831e6bc45112b1ca8a5fcd0fe 100644 --- a/entity/Organisation_entity/entityfields/duplicateactions/children/integratecurrentintoselectedaction/onActionProcess.js +++ b/entity/Organisation_entity/entityfields/duplicateactions/children/integratecurrentintoselectedaction/onActionProcess.js @@ -7,14 +7,14 @@ let sourceContactId = vars.get("$param.DuplicateCurrentContactId_param"); let targetContactId = vars.get("$sys.selection"); //todo the actual merge ought to happen in a separate view where the contact infos can be merged manually by the user. -let mergeSuccess = DuplicateScannerUtils.MergeOrganisation(sourceContactId, targetContactId); +let mergeSuccess = DuplicateScannerUtils.mergeOrganisation(sourceContactId, targetContactId); if(mergeSuccess) { let currentContactId = EmployeeUtils.getCurrentContactId(); if(currentContactId == null) currentContactId = ""; - DuplicateScannerUtils.CreateMergeSuccessActivity(sourceContactId, targetContactId, currentContactId, "Organisation"); + DuplicateScannerUtils.createMergeSuccessActivity(sourceContactId, targetContactId, currentContactId, "Organisation"); neon.openContext("Organisation", "OrganisationMain_view", [targetContactId], neon.OPERATINGSTATE_VIEW, null) } \ No newline at end of file diff --git a/entity/Organisation_entity/entityfields/duplicateactions/children/integrateselectedintocurrentaction/onActionProcess.js b/entity/Organisation_entity/entityfields/duplicateactions/children/integrateselectedintocurrentaction/onActionProcess.js index 0e9b9c71d1fd0afe45f331d3122d07d7de7c4187..824cc9497861d81f6c74e4c5a54fa2203d206964 100644 --- a/entity/Organisation_entity/entityfields/duplicateactions/children/integrateselectedintocurrentaction/onActionProcess.js +++ b/entity/Organisation_entity/entityfields/duplicateactions/children/integrateselectedintocurrentaction/onActionProcess.js @@ -8,13 +8,13 @@ let targetContactId = vars.get("$param.DuplicateCurrentContactId_param"); let sourceContactId = vars.get("$sys.selection"); //todo the actual merge ought to happen in a separate view where the contact infos can be merged manually by the user. -let mergeSuccess = DuplicateScannerUtils.MergeOrganisation(sourceContactId, targetContactId); +let mergeSuccess = DuplicateScannerUtils.mergeOrganisation(sourceContactId, targetContactId); if(mergeSuccess) { let currentContactId = EmployeeUtils.getCurrentContactId(); if(currentContactId == null) currentContactId = ""; - DuplicateScannerUtils.CreateMergeSuccessActivity(sourceContactId, targetContactId, currentContactId, "Organisation"); + DuplicateScannerUtils.createMergeSuccessActivity(sourceContactId, targetContactId, currentContactId, "Organisation"); neon.refreshAll(); } \ No newline at end of file diff --git a/entity/Organisation_entity/recordcontainers/db/onDBDelete.js b/entity/Organisation_entity/recordcontainers/db/onDBDelete.js index 4286e03eb2abd75c156c4b4c45eda9f16f8e084e..730c29c8f1984d5ebc75d045a5ee75779f13a204 100644 --- a/entity/Organisation_entity/recordcontainers/db/onDBDelete.js +++ b/entity/Organisation_entity/recordcontainers/db/onDBDelete.js @@ -7,7 +7,7 @@ import("Attribute_lib"); // TODO: enable when duplicate-module is finalized let contactId = vars.get("$field.CONTACTID"); -DuplicateScannerUtils.DeleteCachedDuplicate(contactId); +DuplicateScannerUtils.deleteCachedDuplicate(contactId); new AttributeRelationQuery(contactId, null, ContextUtils.getCurrentContextId()) .deleteAllAttributes(); diff --git a/entity/Person_entity/entityfields/duplicateactions/children/integratecurrentintoselectedaction/onActionProcess.js b/entity/Person_entity/entityfields/duplicateactions/children/integratecurrentintoselectedaction/onActionProcess.js index c5025d447a3753c2c706b00f3852d2c2efba8b4b..d5f864db525910dd0635ee2ab84279e3346599b6 100644 --- a/entity/Person_entity/entityfields/duplicateactions/children/integratecurrentintoselectedaction/onActionProcess.js +++ b/entity/Person_entity/entityfields/duplicateactions/children/integratecurrentintoselectedaction/onActionProcess.js @@ -8,7 +8,7 @@ var sourceContactId = vars.get("$param.DuplicateCurrentContactId_param"); var targetContactId = vars.get("$sys.selection")[0]; //todo the actual merge ought to happen in a separate view where the contact infos can be merged manually by the user. -var mergeSuccess = DuplicateScannerUtils.MergePerson(sourceContactId, targetContactId); +var mergeSuccess = DuplicateScannerUtils.mergePerson(sourceContactId, targetContactId); if(mergeSuccess) { @@ -21,7 +21,7 @@ if(mergeSuccess) var currentContactId = EmployeeUtils.getCurrentContactId(); if(currentContactId == null) currentContactId = ""; - DuplicateScannerUtils.CreateMergeSuccessActivity(sourceContactId, targetContactId, currentContactId, "Person"); + DuplicateScannerUtils.createMergeSuccessActivity(sourceContactId, targetContactId, currentContactId, "Person"); neon.openContext("Person", "PersonMain_view", [targetContactId], neon.OPERATINGSTATE_VIEW, null) } \ No newline at end of file diff --git a/entity/Person_entity/entityfields/duplicateactions/children/integrateselectedintocurrentaction/onActionProcess.js b/entity/Person_entity/entityfields/duplicateactions/children/integrateselectedintocurrentaction/onActionProcess.js index 8b4940918a56a902ba28f51eb182f7802b6b107e..2930a65370d53abee83d106cae30b08daf67146d 100644 --- a/entity/Person_entity/entityfields/duplicateactions/children/integrateselectedintocurrentaction/onActionProcess.js +++ b/entity/Person_entity/entityfields/duplicateactions/children/integrateselectedintocurrentaction/onActionProcess.js @@ -12,7 +12,7 @@ var sourceContactIdArray = vars.get("$sys.selection"); var sourceContactId = sourceContactIdArray[0]; //todo the actual merge ought to happen in a separate view where the contact infos can be merged manually by the user. -var mergeSuccess = DuplicateScannerUtils.MergePerson(sourceContactId, targetContactId); +var mergeSuccess = DuplicateScannerUtils.mergePerson(sourceContactId, targetContactId); if(mergeSuccess) { @@ -25,7 +25,7 @@ if(mergeSuccess) var currentContactId = EmployeeUtils.getCurrentContactId(); if(currentContactId == null) currentContactId = ""; - DuplicateScannerUtils.CreateMergeSuccessActivity(sourceContactId, targetContactId, currentContactId, "Person"); + DuplicateScannerUtils.createMergeSuccessActivity(sourceContactId, targetContactId, currentContactId, "Person"); // openContext due to the fact, that openContext will lead to an error 'due'cause it's trying to load the already opened preview // of the duplicateContact which just got deleted = nullpointException neon.openContext("Person", null, [targetContactId], neon.OPERATINGSTATE_VIEW, null, null); diff --git a/entity/Person_entity/recordcontainers/db/onDBDelete.js b/entity/Person_entity/recordcontainers/db/onDBDelete.js index db41811d78df66c7f51a6c63749bdeae91f7f26f..aed5eceb442ba9c187b395da25f17467c8a8808b 100644 --- a/entity/Person_entity/recordcontainers/db/onDBDelete.js +++ b/entity/Person_entity/recordcontainers/db/onDBDelete.js @@ -6,7 +6,7 @@ import("system.vars"); import("DuplicateScanner_lib"); var contactId = vars.get("$field.CONTACTID"); -DuplicateScannerUtils.DeleteCachedDuplicate(contactId); +DuplicateScannerUtils.deleteCachedDuplicate(contactId); new AttributeRelationQuery(contactId, null, ContextUtils.getCurrentContextId()) .deleteAllAttributes(); diff --git a/process/DuplicateScanner_lib/process.js b/process/DuplicateScanner_lib/process.js index 9c340dd052bfff736b21ccfe4512e12d85bd5c14..c0f1880e5b01c8f62c8bfc9899ad677687957f19 100644 --- a/process/DuplicateScanner_lib/process.js +++ b/process/DuplicateScanner_lib/process.js @@ -13,6 +13,8 @@ import("system.db"); import("system.entities"); import("Sql_lib"); import("system.indexsearch"); +import("Communication_lib"); +import("Attribute_lib"); /** * Methods for duplicate scanning. @@ -48,7 +50,7 @@ DuplicateScannerUtils.loadFilters = function(pFilterName, pTargetEntity) * * @param {String} pDuplicateId Id of the duplicate to delete */ -DuplicateScannerUtils.DeleteCachedDuplicate = function(pDuplicateId) +DuplicateScannerUtils.deleteCachedDuplicate = function(pDuplicateId) { var [countDuplicatesInClusterWithoutParameterId, clusterId] = newSelect("count(ID), CLUSTERID") .from("DUPLICATECLUSTERS") @@ -615,7 +617,7 @@ DuplicateScannerUtils.TranslateEntityToIndexFields = function(pEntityName, pEnti * @param {String} pTargetContactId The contact in which the source gets integrated * @returns {Boolean} if the merge was sucessful */ -DuplicateScannerUtils.MergePerson = function(pSourceContactId, pTargetContactId) +DuplicateScannerUtils.mergePerson = function(pSourceContactId, pTargetContactId) { var sourcePersonId = newSelect("PERSON_ID") .from("CONTACT") @@ -645,12 +647,12 @@ DuplicateScannerUtils.MergePerson = function(pSourceContactId, pTargetContactId) }); var deletedRows = db.deletes(deleteStatements) - DuplicateScannerUtils.DeleteCachedDuplicate(pSourceContactId); + DuplicateScannerUtils.deleteCachedDuplicate(pSourceContactId); return ((isLinkedDataUpdated || isParticipantsUpdated) && deletedRows > 0); } -DuplicateScannerUtils.CreateMergeSuccessActivity = function(pSourceContactId, pTargetContactId, pCurrentContactId, pContext) +DuplicateScannerUtils.createMergeSuccessActivity = function(pSourceContactId, pTargetContactId, pCurrentContactId, pContext) { var activityDataForInsert = { subject: translate.withArguments("A %0 record has been merged", [pContext]), @@ -664,12 +666,8 @@ DuplicateScannerUtils.CreateMergeSuccessActivity = function(pSourceContactId, pT return ActivityUtils.insertNewActivity(activityDataForInsert, activityLinks, null, db.getCurrentAlias()); } -DuplicateScannerUtils.MergeOrganisation = function(pSourceContactId, pTargetContactId) +DuplicateScannerUtils.mergeOrganisation = function(pSourceContactId, pTargetContactId) { - let updateStatementsCurrentAlias = []; - let updateStatementsSystemAlias = []; - let deleteStatements = []; - var sourceOrganisationId = newSelect("ORGANISATION_ID") .from("CONTACT") .where("CONTACT.CONTACTID", pSourceContactId) @@ -692,7 +690,7 @@ DuplicateScannerUtils.MergeOrganisation = function(pSourceContactId, pTargetCont }); var deletedRows = db.deletes(deleteStatements) - DuplicateScannerUtils.DeleteCachedDuplicate(pSourceContactId); + DuplicateScannerUtils.deleteCachedDuplicate(pSourceContactId); return ((isLinkedDataUpdated || isParticipantsUpdated) && deletedRows >= 2); } @@ -842,11 +840,6 @@ _DuplicateScannerUtils._loadEntityFieldsFromFieldConfigs = function(pEntityField return fieldNames; } -_DuplicateScannerUtils._buildUpdateResetStandardCommunications = function(pSourceContactId) -{ - return newWhere("COMMUNICATION.CONTACT_ID", pSourceContactId).buildUpdateStatement({"ISSTANDARD" : "0"}); -} - /* * Gets the Pattern for the scanner * A pattern usually contains placeholders in the style of "{entityFieldName]" @@ -1160,47 +1153,63 @@ _DuplicateScannerUtils._getIgnoreSourceRecordPattern = function(pRecordIdValueTo _DuplicateScannerUtils._migrateLinkedContactData = function (pSourceContactId, pTargetContactId) { var updateStatements = new Map(); - var resetStandardCommunications = _DuplicateScannerUtils._buildUpdateResetStandardCommunications(pSourceContactId); var currentAlias = db.getCurrentAlias(); - updateStatements.set(currentAlias, [resetStandardCommunications]); - _DuplicateScannerUtils._getLinkedTableInfos.forEach(function ([tableName, columnName, additionalCondition, alias]) + + var setStandardsStatements = []; + var [standardPhone, standardMail, standardAddressId] = newSelect([ + "(" + CommUtil.getStandardSubSqlPhone() + ")", + "(" +CommUtil.getStandardSubSqlMail() + ")", + "CONTACT.ADDRESS_ID" + ]) + .from("CONTACT") + .where("CONTACT.CONTACTID", pTargetContactId) + .arrayRow(); + + //if the targetContact already has a standard phone comm, set the comm from the sourceContact as not standard + if (standardPhone) + { + setStandardsStatements.push( + newWhere("COMMUNICATION.CONTACT_ID", pSourceContactId) + .and("COMMUNICATION.MEDIUM_ID", CommUtil.getMediumIdsByCategory("PHONE"), SqlBuilder.IN()) + .buildUpdateStatement({"ISSTANDARD" : "0"}) + ); + } + if (standardMail) + { + setStandardsStatements.push( + newWhere("COMMUNICATION.CONTACT_ID", pSourceContactId) + .and("COMMUNICATION.MEDIUM_ID", CommUtil.getMediumIdsByCategory("EMAIL"), SqlBuilder.IN()) + .buildUpdateStatement({"ISSTANDARD" : "0"}) + ); + } + //set the standardaddress of the sourceContact as standard of the targetContact if it doesn't have one set yet + if(!standardAddressId) + { + var sourceStandard = newSelect("CONTACT.ADDRESS_ID") + .from("CONTACT") + .where("CONTACT.CONTACTID", pSourceContactId) + .cell(); + setStandardsStatements.push(newWhere("CONTACT.CONTACTID", pTargetContactId).buildUpdateStatement({"ADDRESS_ID": sourceStandard})); + } + + updateStatements.set(currentAlias, setStandardsStatements); + + _DuplicateScannerUtils._getLinkedTableInfos(pTargetContactId).forEach(function ([tableName, columnName, additionalCondition, dbAlias]) { - if (!alias) - alias = currentAlias; + if (!dbAlias) + dbAlias = currentAlias; + + if (!updateStatements.has(dbAlias)) + updateStatements.set(dbAlias, []); + var statements = updateStatements.get(dbAlias); var updateValues = {}; updateValues[columnName] = pTargetContactId; - - var targetStandard = newSelect("CONTACT.ADDRESS_ID") - .from("CONTACT") - .where("CONTACT.CONTACTID", pTargetContactId) - .cell(); - - //set the standardaddress of the sourceContact as standard of the targetContact if it doesn't have one set yet - if(!targetStandard) - { - var sourceStandard = newSelect("CONTACT.ADDRESS_ID") - .from("CONTACT") - .where("CONTACT.CONTACTID", pSourceContactId) - .cell(); - newWhere("CONTACT.CONTACTID", pTargetContactId).updateFields({"ADDRESS_ID": sourceStandard}); - } - var updateCondition = newWhere([tableName, columnName], pSourceContactId).andIfSet(additionalCondition); + var updateCondition = new SqlBuilder(dbAlias).where([tableName, columnName], pSourceContactId).andIfSet(additionalCondition); - //don't use communications that the target already has - if (tableName == "COMMUNICATION") - updateCondition.and(null, newSelect("targetComm.COMMUNICATIONID") - .from("COMMUNICATION", "targetComm") - .where(["COMMUNICATION", "CONTACT_ID", "targetComm"], pTargetContactId) - .and("targetComm.ADDR = COMMUNICATION.ADDR"), - SqlBuilder.NOT_EXISTS()); - - var updateStatement = updateCondition.buildUpdateStatement(updateValues, tableName); - if (updateStatements.has(alias)) - updateStatements.get(alias).push(updateStatement); - else - updateStatements.set(alias, [updateStatement]); + //push must be used here to keep the reference + statements.push(updateCondition.buildUpdateStatement(updateValues, tableName)); }); var totalChanges = 0; @@ -1211,6 +1220,7 @@ _DuplicateScannerUtils._migrateLinkedContactData = function (pSourceContactId, p }); totalChanges += newWhere("COMMUNICATION.CONTACT_ID", pSourceContactId).deleteData(); //delete leftover communications from the source contact + totalChanges += new AttributeRelationQuery(pSourceContactId).deleteAllAttributes(); //delete leftover attributes return totalChanges > 0; } @@ -1220,44 +1230,63 @@ _DuplicateScannerUtils._migrateLinkedContactData = function (pSourceContactId, p * * @returns {String[[]]} Array in the format [TableName, ContactIdColumnName, AdditionalCondition, alias] */ -_DuplicateScannerUtils._getLinkedTableInfos = function() +_DuplicateScannerUtils._getLinkedTableInfos = function(pTargetContactId) { + //don't use communications that the target already has + var communicationDedupCondition = newWhere(null, newSelect("targetComm.COMMUNICATIONID") + .from("COMMUNICATION", "targetComm") + .where(["COMMUNICATION", "CONTACT_ID", "targetComm"], pTargetContactId) + .and("targetComm.ADDR = COMMUNICATION.ADDR"), + SqlBuilder.NOT_EXISTS()); + + //don't use attributes that the contact already has + var targetAttributeSubselect = newSelect("targetAttr.AB_ATTRIBUTERELATIONID") + .from("AB_ATTRIBUTERELATION", "targetAttr") + .where(["AB_ATTRIBUTERELATION", "OBJECT_ROWID", "targetAttr"], pTargetContactId) + .and("targetAttr.AB_ATTRIBUTE_ID = AB_ATTRIBUTERELATION.AB_ATTRIBUTE_ID"); + + AttributeTypeUtil.getAllDatabaseFields().forEach(function (dbColumn) + { + targetAttributeSubselect.and(newWhere("targetAttr." + dbColumn + " = AB_ATTRIBUTERELATION." + dbColumn) + .or("targetAttr." + dbColumn + " is null")); + }); + return[ - ["AB_APPOINTMENTLINK", "OBJECT_ROWID", ""], - ["AB_CTILOG", "CONTACT_ID", ""], - ["AB_OBJECTRELATION", "AB_OBJECTRELATIONID", ""], - ["AB_OBJECTRELATION", "OBJECT1_ROWID", ""], - ["AB_OBJECTRELATION", "OBJECT2_ROWID", ""], - ["AB_LOGHISTORY", "TABLENAMEID", ""], - ["ADDRESS", "CONTACT_ID", ""], - ["BULKMAILRECIPIENT", "CONTACT_ID", ""], - ["BULKMAIL", "TESTING_CONTACT_ID", ""], - ["CAMPAIGN", "EMPLOYEE_CONTACT_ID", ""], - ["CAMPAIGNSTEP", "EMPLOYEE_CONTACT_ID", ""], - ["COMMRESTRICTION", "CONTACT_ID", ""], - ["COMMRESTRICTION", "EMPLOYEE_INVOLVED", ""], - ["COMMUNICATION", "CONTACT_ID", ""], - ["COMPETITION", "CONTACT_ID", ""], - ["CONTRACT", "CONTACT_ID", ""], - ["LETTERRECIPIENT", "CONTACT_ID", ""], - ["OBJECTMEMBER", "CONTACT_ID", ""], - ["OFFER", "CONTACT_ID", ""], - ["PRODUCT", "CONTACT_ID", ""], - ["PRODUCTPRICE", "CONTACT_ID", ""], - ["SALESORDER", "CONTACT_ID", ""], - ["SALESPROJECT", "CONTACT_ID", ""], - ["TASK", "REQUESTOR_CONTACT_ID", ""], - ["TASK", "EDITOR_CONTACT_ID", ""], - ["TASKLINK", "OBJECT_ROWID", ""], - ["ACTIVITY", "RESPONSIBLE", ""], - ["DSGVO", "CONTACT_ID", ""], - ["DSGVOINFO", "CONTACT_ID", ""], - ["TIMETRACKING", "CONTACT_ID", ""], - ["ACTIVITYLINK", "OBJECT_ROWID", ""], - ["AB_ATTRIBUTERELATION", "OBJECT_ROWID", ""], - - ["ASYS_CALENDARLINK", "DBID", "", SqlUtils.getSystemAlias()] - ]; + ["AB_APPOINTMENTLINK", "OBJECT_ROWID"], + ["AB_CTILOG", "CONTACT_ID"], + ["AB_OBJECTRELATION", "AB_OBJECTRELATIONID"], + ["AB_OBJECTRELATION", "OBJECT1_ROWID"], + ["AB_OBJECTRELATION", "OBJECT2_ROWID"], + ["AB_LOGHISTORY", "TABLENAMEID"], + ["ADDRESS", "CONTACT_ID"], + ["BULKMAILRECIPIENT", "CONTACT_ID"], + ["BULKMAIL", "TESTING_CONTACT_ID"], + ["CAMPAIGN", "EMPLOYEE_CONTACT_ID"], + ["CAMPAIGNSTEP", "EMPLOYEE_CONTACT_ID"], + ["COMMRESTRICTION", "CONTACT_ID"], + ["COMMRESTRICTION", "EMPLOYEE_INVOLVED"], + ["COMMUNICATION", "CONTACT_ID", communicationDedupCondition], + ["COMPETITION", "CONTACT_ID"], + ["CONTRACT", "CONTACT_ID"], + ["LETTERRECIPIENT", "CONTACT_ID"], + ["OBJECTMEMBER", "CONTACT_ID"], + ["OFFER", "CONTACT_ID"], + ["PRODUCT", "CONTACT_ID"], + ["PRODUCTPRICE", "CONTACT_ID"], + ["SALESORDER", "CONTACT_ID"], + ["SALESPROJECT", "CONTACT_ID"], + ["TASK", "REQUESTOR_CONTACT_ID"], + ["TASK", "EDITOR_CONTACT_ID"], + ["TASKLINK", "OBJECT_ROWID"], + ["ACTIVITY", "RESPONSIBLE"], + ["DSGVO", "CONTACT_ID"], + ["DSGVOINFO", "CONTACT_ID"], + ["TIMETRACKING", "CONTACT_ID"], + ["ACTIVITYLINK", "OBJECT_ROWID"], + ["AB_ATTRIBUTERELATION", "OBJECT_ROWID", newWhere(null, targetAttributeSubselect, SqlBuilder.NOT_EXISTS())], + + ["ASYS_CALENDARLINK", "DBID", "", SqlUtils.getSystemAlias()] + ]; } /*