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).

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.