0

I have created three fields on Account to store information on the duplicates in the system. Standard duplicate rules apply. The fields are:

  • Duplikat__c: a checkbox
  • ID_Doppelte_Datensaetze__c: Id from the table DuplicateRecordSet
  • Duplikat_Notiz__c: stores information on duplicates

The class to populate the three fields works fine and is as follows:

public class UpdateDuplicateAccounts {

public UpdateDuplicateAccounts(){
    detectAndUpdateDuplicates();    
}

public static void detectAndUpdateDuplicates(){

    //Select all duplicates in the system
    list <DuplicateRecordItem> listDupRecItem = [SELECT DuplicateRecordSetId, Id, IsDeleted, Name, RecordId, DuplicateRecordSet.RecordCount FROM DuplicateRecordItem WHERE IsDeleted = false AND DuplicateRecordSet.RecordCount > 1];
    System.debug(logginglevel.debug, 'Alle Duplikate in der Org: '+listDupRecItem);

    if(listDupRecItem.size() > 0 && listDupRecItem <> null){           

        //get Ids from the corresponding duplicate Accounts
        list <Id> listAccountIds = new list <Id>();
        for (DuplicateRecordItem dupRI: listDupRecItem){
            listAccountIds.add(dupRI.RecordId); 
        }
        System.debug(logginglevel.debug, 'Alle Accounts zu den DuplicateRecordSetIds: '+listAccountIds);

        //Select all newly added duplicate Account records which have not yet been auto-populated
        list <Account> listDuplicateAccounts = [SELECT Id, Duplikat_Notiz__c FROM Account WHERE Id =:listAccountIds AND Duplikat_Notiz__c = ''];
        System.debug(logginglevel.debug, 'Alle Ids von den Account-Duplikaten: '+listDuplicateAccounts);

        //Create new Account list to update records
        list <Account> listAccountsToUpdate = new list <Account>();

        //Check duplicate checkbox and assign Duplicate Id to each Account
        for (DuplicateRecordItem dRI: listDupRecItem) {
            for (Account acct : listDuplicateAccounts){
                if(acct.Id == dRI.RecordId){
                    acct.Duplikat__c = true;
                    acct.ID_Doppelte_Datensaetze__c = dRI.DuplicateRecordSetId;
                    acct.Duplikat_Notiz__c = 'Systemgeneriert';
                    System.debug(logginglevel.debug, 'Account-Update: '+acct);
                    listAccountsToUpdate.add(acct);
                }               
            }
        }

        //update Accounts with information on duplicates
        update listAccountsToUpdate;
    }
}   

}

However, I have problems writing the test class as it seems there is an issue with the order of saving and generating duplicates in the system:

@isTest
  public class UpdateDuplicateAccountsTest {

@isTest
static void clearMessagesTest() {

    //Insert Account
    Account acct = new Account();
    acct.Name = 'Test Account';
    acct.BillingStreet = 'TestStrasse 1';
    acct.BillingCity = 'Test City';
    acct.Phone = '123456789';

    insert acct;

    //Insert duplicate Account
    Database.DMLOptions dml = new Database.DMLOptions(); 
    dml.DuplicateRuleHeader.allowSave = true;
    //dml.DuplicateRuleHeader.runAsCurrentUser = true;
    Account accnt = new Account();
    accnt.Name = 'Test Account';
    accnt.BillingStreet = 'TestStrasse 1';
    accnt.BillingCity = 'Test City';
    accnt.Phone = '123456789';

    Database.SaveResult sr = Database.insert(accnt, dml);
    if (sr.isSuccess()) {
        System.debug('Duplicate account has been inserted in Salesforce!');
    }

    //Run Class to test
    Test.startTest();
        UpdateDuplicateAccounts.detectAndUpdateDuplicates();
    Test.stopTest();

    //Re-Select Duplicate Accounts
    list <Account> listAccount = [SELECT Id, Duplikat__c, ID_Doppelte_Datensaetze__c, Duplikat_Notiz__c FROM Account];
    System.debug(logginglevel.debug, 'Test eingefuegte Accounts'+listAccount);
    list <DuplicateRecordItem> listDupRecItem = [SELECT DuplicateRecordSetId, DuplicateRecordSet.RecordCount FROM DuplicateRecordItem];
    System.debug(logginglevel.debug, 'Test Records in DuplicateRecordItem'+listDupRecItem);

    //Check Checkbox, Id, Note
    //System.assertEquals(true, listAccount[0].Duplikat__c, 'Duplikat nicht angekreuzt');
    //System.assertEquals(listDupRecItem.DuplicateRecordSetId, accnt.ID_Doppelte_Datensaetze__c, 'ID_Doppelte_Datensaetze__c nicht befüllt');
    //System.assertEquals('Systemgeneriert', accnt.Duplikat_Notiz__c, 'Notiz befüllt mit Systemgeneriert');
    //System.assertEquals(200, listDupRecItem.DuplicateRecordSet.RecordCount, 'Notiz befüllt mit Systemgeneriert');
}

}

When I re-select the Accounts in the test class after the test is run on the duplicate Accounts, Duplikat__c is false, both ID_Doppelte_Datensaetze__c and Duplikat_Notiz__c are empty, and there is no entry in the table DuplicateRecordItem.

Is it possible to properly write the test class and make it work? Meaning that the Accounts are really stored as duplicates and identified by the system as such?

0

The DuplicateRecordSet and related objects are not written to the database until a transaction completes, so they cannot be "seen" until such time. To fix this, use testSetup to create the duplicate records, then test the main logic in a unit test. The following change should work:

@isTest public class UpdateDuplicateAccountsTest {

    @testSetup static void testSetupMethod() {
        //Insert Account
        Account acct = new Account();
        acct.Name = 'Test Account';
        acct.BillingStreet = 'TestStrasse 1';
        acct.BillingCity = 'Test City';
        acct.Phone = '123456789';

        insert acct;

        //Insert duplicate Account
        Database.DMLOptions dml = new Database.DMLOptions(); 
        dml.DuplicateRuleHeader.allowSave = true;
        Account accnt = new Account();
        accnt.Name = 'Test Account';
        accnt.BillingStreet = 'TestStrasse 1';
        accnt.BillingCity = 'Test City';
        accnt.Phone = '123456789';

        Database.SaveResult sr = Database.insert(accnt, dml);
        if (sr.isSuccess()) {
            System.debug('Duplicate account has been inserted in Salesforce!');
        }
    }

    @isTest static void clearMessagesTest() {
        //Run Class to test
        Test.startTest();
        UpdateDuplicateAccounts.detectAndUpdateDuplicates();
        Test.stopTest();

        //Re-Select Duplicate Accounts
        list <Account> listAccount = [SELECT Id, Duplikat__c, ID_Doppelte_Datensaetze__c, Duplikat_Notiz__c FROM Account];
        System.debug(logginglevel.debug, 'Test eingefuegte Accounts'+listAccount);
        list <DuplicateRecordItem> listDupRecItem = [SELECT DuplicateRecordSetId, DuplicateRecordSet.RecordCount FROM DuplicateRecordItem];
        System.debug(logginglevel.debug, 'Test Records in DuplicateRecordItem'+listDupRecItem);

        //Check Checkbox, Id, Note
        //System.assertEquals(true, listAccount[0].Duplikat__c, 'Duplikat nicht angekreuzt');
        //System.assertEquals(listDupRecItem.DuplicateRecordSetId, accnt.ID_Doppelte_Datensaetze__c, 'ID_Doppelte_Datensaetze__c nicht befüllt');
        //System.assertEquals('Systemgeneriert', accnt.Duplikat_Notiz__c, 'Notiz befüllt mit Systemgeneriert');
        //System.assertEquals(200, listDupRecItem.DuplicateRecordSet.RecordCount, 'Notiz befüllt mit Systemgeneriert');
    }
}

Here, we simply move the account creation logic to a method with the testSetup annotation, which allows us to have a database commit in place that will allow for the data to be marked as duplicates.

  • Unfortunately it still does not work. Still the Accounts get written into the database, but the duplicate information does not get populated. – user40501 Jul 7 at 16:09
  • @user40501 That should have worked. Have you tried checking your debug logs to ensure the rules are actually firing? – sfdcfox Jul 7 at 17:04
  • Yes, the rule does get invoked, but then the record does not get inserted according to the logs: 23:03:20:016 DUPLICATE_DETECTION_RULE_INVOCATION DuplicateRuleId:0Bm1t000004hCuR|DuplicateRuleName:Standard Account Duplicate Rule|DmlType:INSERT; --- 23:03:20:042 DUPLICATE_DETECTION_MATCH_INVOCATION_DETAILS EntityType:Account|ActionTaken:Allow_[Alert,Report]|DuplicateRecordIds:; --- 23:03:20:042 DUPLICATE_DETECTION_MATCH_INVOCATION_SUMMARY EntityType:Account|NumRecordsToBeSaved:1|NumRecordsToBeSavedWithDuplicates:0|NumDuplicateRecordsFound:0; so do I use the DuplicateRuleHeader wrong? – user40501 Jul 7 at 21:06
  • needs to be said that two Accounts get inserted nevertheless. – user40501 Jul 8 at 4:46
  • @user40501 If the rule is set to block, then allowing the save via header override would be incorrect.I'm not sure the premise of your test is valid. – sfdcfox Jul 8 at 5:30
0

I will answer the question myself. I had to do a manual insert of DuplicateRecordSet and DuplicateRecordItem(s). So the Test Class looks like that:

@isTest

public class Test_DuplicateAccountUpdate {

@testSetup static void testSetupMethod() {
    //Insert Account
    Account acct = new Account();
    acct.Name = 'Test Account';
    acct.BillingStreet = 'TestStrasse 1';
    acct.BillingCity = 'Test City';
    acct.Phone = '123456789';

    insert acct;
    System.debug(logginglevel.debug, 'acct'+acct);

    //Insert duplicate Account
    Database.DMLOptions dml = new Database.DMLOptions(); 
    dml.DuplicateRuleHeader.allowSave = true;
    Account accnt = new Account();
    accnt.Name = 'Test Account';
    accnt.BillingStreet = 'TestStrasse 1';
    accnt.BillingCity = 'Test City';
    accnt.Phone = '123456789';

    Database.SaveResult sr = Database.insert(accnt, dml);
    if (sr.isSuccess()) {
        System.debug(logginglevel.debug, 'accnt'+accnt);
    }


    DuplicateRecordSet dupRS = new DuplicateRecordSet();
    dupRS.DuplicateRuleId = '0Bm0Y0000051YxtSAE';

    insert dupRS;
    System.debug(logginglevel.debug, 'dupRS'+dupRS);

    DuplicateRecordItem dupRIacct = new DuplicateRecordItem();
    dupRIacct.DuplicateRecordSetId = dupRS.Id;
    dupRIacct.RecordId = acct.Id;    

    insert dupRIacct;
    System.debug(logginglevel.debug, 'dupRIacct'+dupRIacct);

    Database.DMLOptions dmlaccnt = new Database.DMLOptions(); 
    dmlaccnt.DuplicateRuleHeader.allowSave = true;

    DuplicateRecordItem dupRIaccnt = new DuplicateRecordItem();
    dupRIaccnt.DuplicateRecordSetId = dupRS.Id;
    dupRIaccnt.RecordId = accnt.Id;    

    Database.SaveResult sraccnt = Database.insert(dupRIaccnt, dmlaccnt);
    if (sraccnt.isSuccess()) {
        System.debug(logginglevel.debug, 'dupRIaccnt'+dupRIaccnt);
    }
}

@isTest static void clearMessagesTest() {
    //Run Class to test
    Test.startTest();
        DuplicateAccountUpdate.detectAndUpdateDuplicates();
    Test.stopTest();

    //Re-Select Duplicate Accounts
    list <Account> listAccount = [SELECT Id, Duplikat__c, ID_Gruppe_doppelter_Datensatz__c, Info_Duplikat__c FROM Account];
    System.debug(logginglevel.debug, 'Test eingefuegte Accounts'+listAccount);
    list <DuplicateRecordItem> listDupRecItem = [SELECT DuplicateRecordSetId FROM DuplicateRecordItem];
    System.debug(logginglevel.debug, 'Test Records in DuplicateRecordItem'+listDupRecItem);
    list <DuplicateRecordSet> listDupRecSet = [SELECT Id, RecordCount FROM DuplicateRecordSet];

    //Check Checkbox, Id, Note
    System.assertEquals(true, listAccount[0].Duplikat__c, 'Duplikat nicht angekreuzt');
    System.assertEquals('Systemgeneriert', listAccount[0].Info_Duplikat__c, 'Notiz befüllt mit Systemgeneriert');
    System.assertEquals(2, listDupRecSet[0].RecordCount, 'Anzahl Records unterschiedlich');
    System.assertEquals(listDupRecItem[0].DuplicateRecordSetId, listDupRecSet[0].Id, 'Ids des Duplicate Record Sets unterschiedlich');
}

}

Furthermore, on the class to be tested I had to change the update into a database.update with DML options as carried out twice in the test class.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.