[SalesForce] Batch apex for account merge DML operation

I have a requirement where I need to merge accounts if a particular field 'vendor_code__c' value is duplicate across the accounts.There is also 2 condition that the :-

1st condition
Account of record type 'A' needs to be the master and record type 'B' needs to be the dupliacate.

2nd condition
If there are only Accounts of record type 'B' with Duplicate vendor codes, then the account with the oldest created date is the master and the rest of the records should be duplicate.

Here I have a working code which works fine for condition 1.I am not sure on how or where to include the second condition.PLz help!

global class BatchVendorAccountMerge implements Database.Batchable<sobject> {

global  Database.QueryLocator start(Database.BatchableContext ctx) {                  
    return Database.getQuerylocator([SELECT Id, Type, RecordTypeId, Record_Type__c, Name, MasterRecordId, Vendor_Code__c FROM Account]); 
}

global void execute(Database.BatchableContext BC, List<Account> accounts ) {


    // Create a map with vendor code and its account
    Map<String, List<Account>> vendorAccountsToMerge = new Map<String, List<Account>>();


    for (Account account : accounts) {

        List<Account> accountsToMerge = vendorAccountsToMerge.get(account.Vendor_Code__c);

        if (accountsToMerge == null) {
            accountsToMerge = new List<Account>();
            vendorAccountsToMerge.put(account.Vendor_Code__c, accountsToMerge);
        }

        if (accountsToMerge.size() < 2) {
            accountsToMerge.add(account);
        } else {

            System.debug('Maximum of accounts to merge reached.');
        }

    }

    System.debug('****vendor and acc map*** ');
    System.debug(vendorAccountsToMerge);

    List<account> dupacc = new list<account>();

    for (String vendorCode : vendorAccountsToMerge.keySet()) {

        List<Account> accountsToMerge = vendorAccountsToMerge.get(vendorCode);

        if (accountsToMerge.size() > 1) {  

            Account masterAccount;
            List<Id> duplicatedAccounts = new List<Id>();           

            for (Account account : accountsToMerge) {

                if (account.Record_Type__c == 'A') {

                    if (masterAccount == null) {
                        masterAccount = account;
                    } else {
                        System.debug('More than one account with the record type A found. Details:');
                        System.debug('Account Ids: ' + masterAccount + ' ' + account.Id);
                    }

                } else if (account.Record_Type__c == 'B') {
                    duplicatedAccounts.add(account.Id);
                }

            }

            System.debug('***Master account*** ' + masterAccount);
            System.debug('***Duplicated accounts*** ' + duplicatedAccounts);

            Database.MergeResult[] results = Database.merge(masterAccount, duplicatedAccounts, false);

            System.debug('***results merged** ' + results);


    }

}

global void finish(Database.BatchableContext BC) {

}

}

Best Answer

There's more than one way to solve this problem, and you certainly could do it by iterating over the Account list within the trigger:

        Account candidateMasterAccount = null;
        for (Account account : accountsToMerge) {

            if (account.Record_Type__c == 'A') {

                if (masterAccount == null) {
                    masterAccount = account;
                } else {
                    System.debug('More than one account with the record type A found. Details:');
                    System.debug('Account Ids: ' + masterAccount + ' ' + account.Id);
                }

            } else if (account.Record_Type__c == 'B') {
                if (candidateMasterAccount == null || account.CreatedDate < candidateMasterAccount.CreatedDate) {
                    candidateMasterAccount = account;
                }
                duplicatedAccounts.add(account.Id);
            }
        }

Then , before performing your merge, you'd check to see if masterAccount was null. If so, you'd drop through to see if candidateMasterAccount was not null, and if it wasn't, you'd remove it from duplicatedAccounts and use it as the master in your merge.

Another way to approach this would be to write a small wrapper class that stores a single Account and implements the Comparable interface. Your compareTo method could then implement this logic to sort the right Account to the front of the list, comparing by record type first and then created date, and you'd find the master account by simply sorting the list and taking the first entry as master.

I think there's a deeper issue with your batch class, though, and it's that you're only going to find duplicates if they happen to be in the same batch context (200 records by default). I think you're going to need to use an ORDER BY clause (with some logic to check for cases where Accounts with the same vendor are split across invocations) or perhaps an aggregate query.

Related Topic