2

I am writing a trigger for the beforeInsert event of the Opportunity object. What I am trying to achieve is, generating a value for one of the Opportunity's custom fields(Ref__c), that is, a concatenation of a field of the Opportunity's Account(Codigo_Socio__c) and an 'auto-increment' number(numberCode), that will increment, based on the quantity of the inserted opportunities for this account.

(e.g An Account with Codigo_Socio__c = 'BCN-0001', if two Opportunities are going to be inserted, their Ref__c fields would have to result to the following values, respectively: BCN0001-1, BCN0001-2.

Below, is the method I am trying to implement to control the logic for this task.

public void generateRefCode(List<Opportunity> newList)
{

         Integer numberCode = 1;
         String[] numberCodeParts;

        //map-Opportunities with their Accounts
        //Key= AccountId ; Value=Opportunity
        Map<Id, Opportunity> mapAccountsWithOpps = new Map<Id,Opportunity>();

        // Now let's get the accountIds
        Set<Id> accountIds = new Set<Id>();
        for(Opportunity op : newList){
            accountIds.add(op.AccountId);
        }

        //obtain opportunities from the existing accounts
        Map<Id, Opportunity> mapOpps = new Map<Id,Opportunity>([SELECT AccountId, Ref__c FROM Opportunity  
                                                                Where AccountId in : accountIds]);

         //get the existing accounts as well from the database
         Map<Id, Account> mapAccounts = new Map<Id,Account> ([Select Id, Codigo_Socio__c, Name FROM Account Where Id in : accountIds]);

        //Put them together
        for(Id accountId: mapOpps.keySet()){

            if(mapAccounts.containsKey(accountId)){
                Opportunity op = mapOpps.get(accountId);
                mapAccountsWithOpps.put(accountId, op);
            }
        }



            //we iterate over the newly inserted opportunities
            for(Opportunity opp: newList)
            {

                  //case 1 :no opps so far for this account
                 if(!mapAccountsWithOpps.containsKey(opp.AccountId)){

                        //we obtain the corresponding account via its Id
                        Account acct = mapAccounts.get(opp.AccountId);

                        //concatenate strings for the Ref field(CodigoSocio + number)   
                        opp.Ref__c = acct.Codigo_Socio__c + '-' + String.valueOf(numberCode);
                        numberCode++;

                        System.debug('@@Ref generated: ' + opp.Ref__c );


                        //we add the account in the list accountsWithOpps 
                        mapAccountsWithOpps.put(opp.AccountId, opp);      
                  }


                 else{


                        Opportunity lastOpp = mapAccountsWithOpps.get(opp.AccountId);

                        //we obtain the corresponding account via its Id
                        Account acct = mapAccounts.get(lastOpp.AccountId);
                        System.debug('@@Last added opp for Account ' + acct.Name + ', oppRef: ' + lastOpp.Ref__c);


                        if(!String.isEmpty(lastOpp.Ref__c)){

                            numberCodeParts = lastOpp.Ref__c.split('-');
                            String numberPart = numberCodeParts[1].trim();

                            numberCode = Integer.valueOf(numberPart);
                            numberCode++;


                            opp.Ref__c = acct.Codigo_Socio__c + '-' + numberCode;

                            System.debug('@@Ref generated ' + opp.Ref__c);

                            //we remove the last added opp for this accountId
                            mapAccountsWithOpps.remove(lastOpp.AccountId);
                            mapAccountsWithOpps.put(opp.AccountId, opp);

                        }

                  }     
            }   

}   

I first proceed to this , by querying the existing opportunities and accounts from the database, and map them together in the map Map<Id, Opportunity> mapAccountsWithOpps = new Map<Id,Opportunity>(); so I can keep track of the accounts that already have opportunities. And then on the iteration of newList (i.e actually, Trigger.new that I pass it from my trigger handler class) I create the condition, that, if the corresponding opportunity does not have an Account mapped already in the aforementioned map, I add it to the map. Else, I retrieve the last opportunity, added to that Account so I can obtain the numberCode , increment it and put the new Opportunity along with its AccountId key in the map.

One of the problems that I observed my implementation has , whilst running its corresponding test and debugging as well, is that the following lines of code are totally omitted when an insertion happens:

//Put them together
    for(Id accountId: mapOpps.keySet()){

        if(mapAccounts.containsKey(accountId)){
            Opportunity op = mapOpps.get(accountId);
            mapAccountsWithOpps.put(accountId, op);
        }
    }

It has been a while now that I am having a hard time on this one and even though I have tried other implementations and approaches, apart from the aforementioned method logic,(e.g execute an SOQL statement for Account that, with a subquery in it, so the Account's Opportunities could be obtained at the same time),

I am still failing to see clearly, where my head's bug for this trigger lurks!
Any help/suggestion would be much appreciated. Thank you.

2 Answers 2

0

Based on your requirements, I believe what you are looking at doing is creating a Map of Account Ids to a List of Related Opportunities. If my assumption is correct then your mapAccountsWithOpps should look like this:

Map<Id,List<Opportunity>> mapAccountWithOpps = new Map<Id,List<Opportunitiy>>();

To populate the above map you after you query for the opportunities(a list should be sufficient) you could just iterate over that list to populate your map like this:

for(Opportunity opp : listOpps) {
    if(mapAccountWithOpps.containsKey(opp.AccountId)){
        mapAccountWithOpps.get(opp.AccountId).add(opp);
    } else {
        mapAccountWithOpps.put(opp.AccountId, new List<Opportunity>{opp});
    }
}  

You should then be able to iterate over the above map and inner loop on the list to set your reference numbers.

0

I think you could use a Flow (fired by Process Builder) for this. What you need to do is to use a Loop to count the number of records associated to this Opportunity. Your first element would be a Record Lookup on the Opportunity to find the AccountId. After that you want to do a Lookup on the Account to find the Account Codigo_Socio__c field. Then do Fast Lookup of Opportunities with the AccountId your Opportunity has, and then have the Loop funnel through an Assignment Rule where you add +1 to a variable with every "record" that is passed through. Since this newly created Opportunity would be in there, you would have it finish with the correct "#" that you need for the last part of your Ref__c field. So, you would do a variable that combines the two into one field doing "Codigo_Socio__c"&"-"&"#"" as your value to insert into Ref__c on your Opportunity (through a record update).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .