+ Start a Discussion
wcwill978wcwill978 

Opportunity trigger to update other opportunites when one is closed

Hi I am trying to write a trigger that will update all other open opportunities within the same account when one is closed. Right now we have workflow that sets the opportunity type based on some categories. If ten opportunities open for the same account they are automatically set to "Initial Purchase".

 

What I want to do is have a trigger run when one opportunity is closed won to update the other nine open opportunities to a different type. So the one that closes remains as Initial Purchase, but the other nine change to Existing Customer since they have already purchased from us.

 

Here is what I have so far, but when I close an opportunity as closed won it does not update the other open opportunities for the related account:

 

trigger updateOpportunityType on Opportunity (after update) 
{



// Build a map from the Opportunity ID's referenced in the Accounts for a reverse lookup later.
    Set<Id> OpptyIds = new Set<Id>();
    for (Opportunity opps: trigger.new) 
    if (opps.AccountId != null) 
    OpptyIds.add(opps.AccountId);
    
//Build a list of all open opportunities in the map.    
    List<Opportunity> opptys = new List<Opportunity>([select Id, Type FROM Opportunity 
                                WHERE Type = 'New Customer – Initial PurchaseId'
                                AND isClosed = false
                                AND Id in :OpptyIds]);
                                
//Build a list of the opportunity that is closing.
    List<Opportunity> closedoppty = new List<Opportunity>([select Id, Type FROM Opportunity 
                                WHERE Type = 'New Customer – Initial PurchaseId'
                                AND isClosed = true
                                AND StageName = 'Closed Won'
                                AND Id in :OpptyIds]);

    for (Opportunity openopps: opptys)
    {
        if(!closedoppty.isEmpty())
        {
            openopps.Type = 'New Customer – First 12 Months';
        }
    
    }
    
    update opptys;
    
}

 

Thanks.

bob_buzzardbob_buzzard

Your opptyids is populated with account ids on this line:

 

 OpptyIds.add(opps.AccountId);
    

 

but then you use it to constrain the selection of opportunities:

 

//Build a list of all open opportunities in the map.    
List<Opportunity> opptys = new List<Opportunity>([select Id, Type FROM Opportunity 
                    WHERE Type = 'New Customer – Initial PurchaseId'
                    AND isClosed = false
                    AND Id in :OpptyIds]);

 I'd expect the opptys list to be empty after this call, as there won't be any opportunities with an account specific id.

shikher goelshikher goel
trigger updateOpportunityType on Opportunity (after update) 
{



// Build a map from the Opportunity ID's referenced in the Accounts for a reverse lookup later.
    Set<Id> OpptyIds = new Set<Id>();
    for (Opportunity opps: trigger.new) 
    if (opps.AccountId != null) 
    OpptyIds.add(opps.AccountId); //IN THIS STATEMENT YOU ARE ADDING ACCOUNT ID'S
    
//Build a list of all open opportunities in the map.    
    List<Opportunity> opptys = new List<Opportunity>([select Id, Type FROM Opportunity 
                                WHERE Type = 'New Customer – Initial PurchaseId'
                                AND isClosed = false
                                AND Id in :OpptyIds]); // AND HERE YOU SEARCHING FOR THE
//Id in:AccountIds.
//Correct query should be like this:
   List<Opportunity> opptys = new List<Opportunity>([select Id, Type FROM Opportunity 
                                WHERE Type = 'New Customer – Initial PurchaseId'
                                AND isClosed = false
                                AND AccountId in :OpptyIds]);

                                
//Build a list of the opportunity that is closing.
    List<Opportunity> closedoppty = new List<Opportunity>([select Id, Type FROM Opportunity 
                                WHERE Type = 'New Customer – Initial PurchaseId'
                                AND isClosed = true
                                AND StageName = 'Closed Won'
                                AND Id in :OpptyIds]);//SAME MISTAKE

    for (Opportunity openopps: opptys)
    {
        if(!closedoppty.isEmpty())
        {
            openopps.Type = 'New Customer – First 12 Months';
        }
    
    }
    
    update opptys;
    
}
wcwill978wcwill978

Hi Bob,

 

Every opportunity has a related account. An Account can have unlimited opportunities. What i want to do is build a map or set of all the open opportunity ID's for one account. Then when one of those open opportunities close I want to update the remaining open opportunities with the same Account ID to First 12 months. Right now when I close an opportunity its not updating the other opportunities on that account

 

@shikgoel: I tried your suggestion and still it did not work. Im testing with ana ccount with three open opportunities when i close one as won it should change th other two opportunites to New Customer – First 12 Months?

 

Thank you guys for you suggestions/help.

bob_buzzardbob_buzzard

You probably want to change your query so that it checks if the opportunity account id = the opptyids list (that actually contain the account ids) - that will pull back all opportunities with a parent account in the list.

wcwill978wcwill978

I got this to work now and its updating all the other open opportunities as it should. Now I am also trying to update the account and cant seem to get it to update a date field when it meets the criteria. Below is the latest code:

 

trigger updateOpportunityType on Opportunity (after update) 
{

// Build a map from the Opportunity ID's referenced in the Accounts for a reverse lookup later.
    Set<Id> AcctIds = new Set<Id>();
    for (Opportunity opps: trigger.new) 
    if (opps.ForecastCategoryName == 'Closed' && opps.StageName == 'Closed Won') 
    AcctIds.add(opps.AccountId);  //ADDING ACCOUNT ID'S 
    
//Build a list of all open opportunities in the map.
   List<Opportunity> opptys = new List<Opportunity>([select Id, AccountId, StageName, Type FROM Opportunity 
                                WHERE Type = 'New Customer – Initial Purchase'
                                AND isClosed = false
                                AND StageName != 'Closed Won'
                                AND AccountId in :AcctIds]);
                                
   List <Account> accts = new List<Account>([SELECT Id, Total_Won_Opportunities__c, First_Won_Opportunity__c, Type
                                                FROM Account
                                                WHERE RecordTypeId != '012300000000Dk1'
                                                AND Id in :AcctIds]);

    for (Opportunity openopps: opptys)
    {
    
        for (Id thisId : AcctIds)
        {
            if (thisId == openopps.AccountId)
            openopps.Type = 'New Customer – First 12 Months'; 
        }
    }
//Here I want to update the account for the affected opportunities, if the opportunity closing is the first then set the First Won Opportunity date    
    for (Account acct: accts)
    {
    
    if (acct.Total_Won_Opportunities__c == 1)
    acct.First_Won_Opportunity__c = System.today();
    
    }
    
    update opptys;
    update accts;
    
}

How can I get this to also update the account?

bob_buzzardbob_buzzard

Is Total_Won_Opportunities__c a roll up summary field?  If so, this won't be updated until later in the transaction according to the order of execution in the apex developer's guide.  The after triggers (which is what your trigger is) run, and then the roll up summary fields on the parent record get updated.

wcwill978wcwill978

 

I got it to update the account also with this. The problem I am facing now is that it updates the account every single time. What am I doing wrong how can i get it to update only when Total Won Opportunities = 1, and yes this is a roll-up summary field. i have other triggers that use roll-up summary fields and they update correctly based on the summary field.

 

 

trigger updateOpportunityType on Opportunity (after update) 
{

// Build a map from the Opportunity ID's referenced in the Accounts for a reverse lookup later.
    Set<Id> AcctIds = new Set<Id>();
    Set<Id> firstOpptyAccountIds = new Set<Id>();
    
    for (Opportunity opps: trigger.new) 
    if (opps.ForecastCategoryName == 'Closed' && opps.StageName == 'Closed Won') 
    AcctIds.add(opps.AccountId);  //ADDING ACCOUNT ID'S IN THIS STATEMENT 
    
    //for (Opportunity oppUpdate : trigger.new)
    //if (oppUpdate.Type != 'New Customer – First 12 Months' && oppUpdate.StageName == 'Closed Won') 
    //  firstOpptyAccountIds.add(oppUpdate.AccountId); 
    
    
    
//Build a list of all open opportunities in the map.
   List<Opportunity> opptys = new List<Opportunity>([select Id, AccountId, StageName, Type FROM Opportunity 
                                WHERE Type = 'New Customer – Initial Purchase'
                                AND isClosed = false
                                AND StageName != 'Closed Won'
                                AND AccountId in :AcctIds]);
                                
   List <Account> updateAccounts = new List<Account>([SELECT Id, Total_Won_Opportunities__c, First_Won_Opportunity__c, Type
                                                FROM Account
                                                WHERE RecordTypeId != '012300000000Dk1'
                                                AND Total_Won_Opportunities__c = 1
                                                AND Id in :AcctIds]);

    for (Opportunity openopps: opptys)
    {
    
        for (Id thisId : AcctIds)
        {
            if (thisId == openopps.AccountId)
            openopps.Type = 'New Customer – First 12 Months'; 
        }
    }
    
    for  (Account acct : updateAccounts)
    {
            //for (Id thisAcctId : AcctIds)
            //{
                //if (thisAcctId == acct.Id)
                if (acct.Total_Won_Opportunities__c == 1)
                {
                acct.First_Won_Opportunity__c = System.today();
                }
            //}
    
    }
    
    update opptys;
    update updateAccounts;
    
}
bob_buzzardbob_buzzard

When you say it updates the accounts every time, does is set the first won opportunity date every time, or simply apply an update to the record?