function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
sumit dsumit d 

prevent duplicate accounts creation in a batch


 Hi All,
        i have a batch in which i am creating a parent child account hierarchy.  at this time when i am executing the batch for opportunity with exact same name its creating two Accounts with the same name but i want that opportunity with same name should go to the account which is first created .it should not created duplicate records of Account for opportunity with same name.
my batch is given below:- 

 public class BatchResellerPartnerToResellerCustomer implements Database.Batchable<sObject>{
    //Run method to check the Batch on one record
    public static void run( Set<Id> OppIds ) {
         List<Opportunity> OppRecords =  [SELECT Name, AccountId, 
                                         Account.Name, Account.OwnerId,
                                         Account.RecordTypeId, Account.RecordType.Name  
                                         FROM Opportunity 
                                         WHERE AccountId != null 
                                         AND Account.RecordType.Name = 'Time Rack'
                                         AND Account.Customer_Type__c = 'Reseller'
                                         AND Id IN:  OppIds ];
        
        executeHelper( OppRecords );                  
    }
    public Database.querylocator start(Database.BatchableContext BC){
        String query = 'SELECT Name, Account.Name, Account.OwnerId, AccountId, '+
            'Account.RecordTypeId, Account.RecordType.Name '+
            'FROM Opportunity '+
            'WHERE AccountId != null '+
            'AND Account.RecordType.Name = \'Time Rack\''+
            'AND Account.Customer_Type__c = \'Reseller\'';
        return Database.getQueryLocator(query);            
    }
    public void execute(Database.BatchableContext BC, List<Opportunity> scope){
         executeHelper( scope );
    }
    //Helper method to create  respective Accounts of opportunities
    public static void executeHelper( List<Opportunity> scope ) {
        List<Account> accList = new List<Account>();
        List<Opportunity> opptyListToBeUpdated = new List<Opportunity>();
        //Create Accounts with Opportunity's EndUser Name and ParentId with Opp's accountId
        for(Opportunity Oppty : scope) {
             String oppName = '';
             //Condition to get the end user name from opp name and give it to the new Account
            if(Oppty.Name.startsWith(Oppty.Account.Name)){
                oppName = Oppty.Name.removeStart(Oppty.Account.Name);
                oppName = oppName.trim();
                 if(oppName.startsWith(':') ){
                    oppName = oppName.substringAfter(':');
                    oppName = oppName.trim();
                }
                else if( oppName.startsWith('-') ){
                    oppName = oppName.substringAfter('-');
                    oppName = oppName.trim();
                }
                else{
                    oppName = Oppty.Name;
                }
            }
            //Condition to check opportunity has account with record type
            if(oppName != '' 
               && Oppty.AccountId != Null
               && Oppty.Account.RecordTypeId != Null){
                   //create new Account for each opportunity with customerType -'End user'
                 Account acc = new Account(Parentid = Oppty.AccountId,
                                            Customer_Type__c = 'End User',
                                            RecordTypeId = Oppty.Account.RecordTypeId,
                                            OwnerId = Oppty.Account.OwnerId,
                                            Name = oppName );
                accList.add(acc);
            }
            
         }
        if(accList.size()>0) {
            insert accList;
        }
         // Update Oppty List with newAccountId
        for(Account acc : accList) {
            for(Opportunity oppty : scope) {
               if(oppty.AccountId == acc.ParentId) {
                    oppty.AccountId = acc.Id;
                    opptyListToBeUpdated.add(oppty);
                 }
            }
        }
        if(opptyListToBeUpdated.size()>0) {
            update opptyListToBeUpdated;
        }
    }
    public void finish(Database.BatchableContext BC){
    }
}
         right now its creating duplicate account records with opportunity which has same name.i want to prevent duplicate account creation and simply want that the opportunity should attach with the account which is created already first with the batch.
How can i modify this batch to prevent duplicate accounts creations?
Any suggestions?
Best Answer chosen by sumit d
DheerajKumar@SalesforceDheerajKumar@Salesforce
Hi Sumit,

Try with below updated code. Created one map of account name and account so through this map it will prevent duplicate records to be created.
 
public class BatchResellerPartnerToResellerCustomer implements Database.Batchable<sObject>{
    //Run method to check the Batch on one record
    public static void run( Set<Id> OppIds ) {
         List<Opportunity> OppRecords =  [SELECT Name, AccountId, 
                                         Account.Name, Account.OwnerId,
                                         Account.RecordTypeId, Account.RecordType.Name  
                                         FROM Opportunity 
                                         WHERE AccountId != null 
                                         AND Account.RecordType.Name = 'Time Rack'
                                         AND Account.Customer_Type__c = 'Reseller'
                                         AND Id IN:  OppIds ];
        
        executeHelper( OppRecords );                  
    }
    public Database.querylocator start(Database.BatchableContext BC){
        String query = 'SELECT Name, Account.Name, Account.OwnerId, AccountId, '+
            'Account.RecordTypeId, Account.RecordType.Name '+
            'FROM Opportunity '+
            'WHERE AccountId != null '+
            'AND Account.RecordTypeId= \'Time Rack\''+
            'AND Account.Customer_Type__c = \'Reseller\'';
        return Database.getQueryLocator(query);            
    }
    public void execute(Database.BatchableContext BC, List<Opportunity> scope){
         executeHelper( scope );
    }
    //Helper method to create  respective Accounts of opportunities
    public static void executeHelper( List<Opportunity> scope ) {
        Map<String, Account> accMap = new Map<String, Account>();
        List<Opportunity> opptyListToBeUpdated = new List<Opportunity>();
        //Create Accounts with Opportunity's EndUser Name and ParentId with Opp's accountId
        for(Opportunity Oppty : scope) {
            String oppName = getOpptyName(Oppty);
            //Condition to check opportunity has account with record type
            if(oppName != '' && !accMap.containsKey(oppName)
               && Oppty.AccountId != Null
               && Oppty.Account.RecordTypeId != Null){
                   //create new Account for each opportunity with customerType -'End user'
                 Account acc = new Account(Parentid = Oppty.AccountId,
                                            Customer_Type__c = 'End User',
                                            RecordTypeId = Oppty.Account.RecordTypeId,
                                            OwnerId = Oppty.Account.OwnerId,
                                            Name = oppName );
                accMap.put(oppName, acc);
            }
            
         }
        if(accMap.size()>0) {
            insert accMap.values();
        }
         // Update Oppty List with newAccountId
        for(Opportunity oppty : scope) {
            String oppName = getOpptyName(oppty);
            if(accMap.containsKey(oppName)) {
                oppty.AccountId = accMap.get(oppName).Id;
                opptyListToBeUpdated.add(oppty);
            }
        }
        if(opptyListToBeUpdated.size()>0) {
            update opptyListToBeUpdated;
        }
    }
    
    private static String getOpptyName(Opportunity Oppty) {
        String oppName = '';
        //Condition to get the end user name from opp name and give it to the new Account
        if(Oppty.Name.startsWith(Oppty.Account.Name)){
            oppName = Oppty.Name.removeStart(Oppty.Account.Name);
            oppName = oppName.trim();
            if(oppName.startsWith(':') ){
                oppName = oppName.substringAfter(':');
                oppName = oppName.trim();
            }
            else if( oppName.startsWith('-') ){
                oppName = oppName.substringAfter('-');
                oppName = oppName.trim();
            }
            else{
                oppName = Oppty.Name;
            }
        }
        return oppName;
    }
    
    public void finish(Database.BatchableContext BC){
    }
}

If above code will solve your problem then mark this as best answer. Let me know if there any further help required on the same.

Thanks
Dheeraj
 

All Answers

DheerajKumar@SalesforceDheerajKumar@Salesforce
Hi Sumit,

Try with below updated code. Created one map of account name and account so through this map it will prevent duplicate records to be created.
 
public class BatchResellerPartnerToResellerCustomer implements Database.Batchable<sObject>{
    //Run method to check the Batch on one record
    public static void run( Set<Id> OppIds ) {
         List<Opportunity> OppRecords =  [SELECT Name, AccountId, 
                                         Account.Name, Account.OwnerId,
                                         Account.RecordTypeId, Account.RecordType.Name  
                                         FROM Opportunity 
                                         WHERE AccountId != null 
                                         AND Account.RecordType.Name = 'Time Rack'
                                         AND Account.Customer_Type__c = 'Reseller'
                                         AND Id IN:  OppIds ];
        
        executeHelper( OppRecords );                  
    }
    public Database.querylocator start(Database.BatchableContext BC){
        String query = 'SELECT Name, Account.Name, Account.OwnerId, AccountId, '+
            'Account.RecordTypeId, Account.RecordType.Name '+
            'FROM Opportunity '+
            'WHERE AccountId != null '+
            'AND Account.RecordTypeId= \'Time Rack\''+
            'AND Account.Customer_Type__c = \'Reseller\'';
        return Database.getQueryLocator(query);            
    }
    public void execute(Database.BatchableContext BC, List<Opportunity> scope){
         executeHelper( scope );
    }
    //Helper method to create  respective Accounts of opportunities
    public static void executeHelper( List<Opportunity> scope ) {
        Map<String, Account> accMap = new Map<String, Account>();
        List<Opportunity> opptyListToBeUpdated = new List<Opportunity>();
        //Create Accounts with Opportunity's EndUser Name and ParentId with Opp's accountId
        for(Opportunity Oppty : scope) {
            String oppName = getOpptyName(Oppty);
            //Condition to check opportunity has account with record type
            if(oppName != '' && !accMap.containsKey(oppName)
               && Oppty.AccountId != Null
               && Oppty.Account.RecordTypeId != Null){
                   //create new Account for each opportunity with customerType -'End user'
                 Account acc = new Account(Parentid = Oppty.AccountId,
                                            Customer_Type__c = 'End User',
                                            RecordTypeId = Oppty.Account.RecordTypeId,
                                            OwnerId = Oppty.Account.OwnerId,
                                            Name = oppName );
                accMap.put(oppName, acc);
            }
            
         }
        if(accMap.size()>0) {
            insert accMap.values();
        }
         // Update Oppty List with newAccountId
        for(Opportunity oppty : scope) {
            String oppName = getOpptyName(oppty);
            if(accMap.containsKey(oppName)) {
                oppty.AccountId = accMap.get(oppName).Id;
                opptyListToBeUpdated.add(oppty);
            }
        }
        if(opptyListToBeUpdated.size()>0) {
            update opptyListToBeUpdated;
        }
    }
    
    private static String getOpptyName(Opportunity Oppty) {
        String oppName = '';
        //Condition to get the end user name from opp name and give it to the new Account
        if(Oppty.Name.startsWith(Oppty.Account.Name)){
            oppName = Oppty.Name.removeStart(Oppty.Account.Name);
            oppName = oppName.trim();
            if(oppName.startsWith(':') ){
                oppName = oppName.substringAfter(':');
                oppName = oppName.trim();
            }
            else if( oppName.startsWith('-') ){
                oppName = oppName.substringAfter('-');
                oppName = oppName.trim();
            }
            else{
                oppName = Oppty.Name;
            }
        }
        return oppName;
    }
    
    public void finish(Database.BatchableContext BC){
    }
}

If above code will solve your problem then mark this as best answer. Let me know if there any further help required on the same.

Thanks
Dheeraj
 
This was selected as the best answer
sumit dsumit d
Hi Deeraj,
 i made the test class for it given below:-
 
@isTest
private class BatchResellerCustomerTest {
    static testmethod void TestResellerCustomer(){
        
        // Create Account with recordType-"Timerack" and customer type-"Reseller"
        Id recId = Schema.SObjectType.Account.getRecordTypeInfosByName().get('Time Rack').getRecordTypeId();
        Account acc =new Account( Name = 'test' ,Customer_Type__c ='Reseller' ,recordtypeid = recId ); 
        insert acc;
        
        //Create opportunity with the Account Opportunity Name with '-'
        Opportunity opp = new Opportunity();
        opp.StageName = 'Sourcing Demand';
        opp.AccountId = acc.id;
        opp.CloseDate =  System.today();
        opp.Name = 'test -ExPay';
        insert opp;
         
        // Opportunity Name with ':'
        Opportunity oppt = new Opportunity();
        oppt.StageName = 'Sourcing Demand';
        oppt.AccountId = acc.id;
        oppt.CloseDate =  System.today();
        oppt.Name = 'test :RePay';
        insert oppt;
        
        //opportunity Name other than '-' and ':'
        Opportunity oppty = new Opportunity();
        oppty.StageName = 'Sourcing Demand';
        oppty.AccountId = acc.id;
        oppty.CloseDate =  System.today();
        oppty.Name = 'test Pay';
        insert oppty;
        
        //Opportunity with same name
        Opportunity opp1 = new Opportunity();
        opp1.StageName = 'Sourcing Demand';
        opp1.AccountId = acc.id;
        opp1.CloseDate =  System.today();
        opp1.Name = 'test -ExPay';
        insert opp1;
        
        //Opportunity with some other notation
        Opportunity opp2 = new Opportunity();
        opp2.StageName = 'Sourcing Demand';
        opp2.AccountId = acc.id;
        opp2.CloseDate =  System.today();
        opp2.Name = 'test =ExPay';
        insert opp2;
        
        //Execute the test methods
        test.startTest();
        BatchResellerPartnerToResellerCustomer obj = new BatchResellerPartnerToResellerCustomer();
        database.executeBatch(obj);
        Set<Id> OppIds = new Set<Id>();
        OppIds.add(opp.Id);
        BatchResellerPartnerToResellerCustomer.run(OppIds);
        test.stopTest();
        List<Account> accList =  [Select id,Name from Account where ParentId=:acc.id];
        System.assertEquals('ExPay', accList[0].Name);
        System.assertEquals('RePay', accList[1].Name);
        System.assertEquals('test Pay', accList[2].Name);
        System.assertEquals('ExPay', accList[3].Name);
        System.assertEquals('test =ExPay', accList[4].Name);
     }
}
i am not able to understand that the asserts i created is correct or not?
Can you help me out with it?
DheerajKumar@SalesforceDheerajKumar@Salesforce
Hi Sumit,

I am hoping that in my given code you have replaced this code line number 20 'AND Account.RecordTypeId= \'Time Rack\'' to 'AND Account.RecordType.Name= \'Time Rack\''.

There will be only one account will gets created for ExPay account name. Which you have asserted in first assert.
So in this above test class total 4 accounts gets created with below names :
  1. ExPay
  2. RePay
  3. test Pay
  4. test =ExPay
You could also put a first assert after fetching the account as below which will verify how many accounts got created in batch. So your final assert will be like below :
System.assertEquals(4, accList.size());
System.assertEquals('ExPay', accList[0].Name);
System.assertEquals('RePay', accList[1].Name);
System.assertEquals('test Pay', accList[2].Name);
System.assertEquals('test =ExPay', accList[3].Name);

Hope above will solve your problem, Hit like if this will help you.

Thanks
Dheeraj Kumar
 
sumit dsumit d
Hi Dheeraj,
my first assertion is failing Assertion Failed: Expected: 4, Actual: 5
Any suggestions?
DheerajKumar@SalesforceDheerajKumar@Salesforce
Hi Sumit,

I have looked into your test class code. For a batch class test method, batch will be completed once code execution reached at Test.stopTest(). Rather then calling run method in b/w Test.startTest() and Test.stopTest(). You need to call run method after Test.stopTest().

Below code needs to be moved after Test.stopTest();

Set<Id> OppIds = new Set<Id>();
OppIds.add(opp.Id);
BatchResellerPartnerToResellerCustomer.run(OppIds);

Because in run method the opportunity id which you are passing will get one opportunity which have the Customer Type as Reseller.

Hope above will solve your problem, Hit like if this will help you.

Thanks
Dheeraj Kumar