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
cambart14cambart14 

Change Status on Projects when Opportunity is Closed

On some of our Opportunites we can have multiple 'active' projects that we would like change the status to 'complete' when its opportunity is marked as 'Won' or 'Lost'.  I have looked at doing this through the Workflow, but it does not seem robust enought to accomplish this.  Would I be able to accomplish this through a trigger?  If not, any other suggestions are welcome.  Thanks for your help!

Best Answer chosen by Admin (Salesforce Developers) 
JitendraJitendra

Hi, 

Here your code :

 

trigger closeRelatedItems on Opportunity (after insert, after update) {

    Set<ID> oppIds = new Set<ID>();
    for(Opportunity o: Trigger.new)
	{
		if(o.stage__c="Won" || o.stage__c="Lost")
		{
			oppIds.add(o.id);
		}
	}
	
    //replace field "parentOpportunity__c " with actual field name which is lookup to opportunity
    List<Project__c> ProductsToUpdate = [SELECT ID, Status__c  FROM Project__c WHERE parentOpportunity__c IN : oppIds];
    for(Project__c ol: ProductsToUpdate)
    {ol.Status__c = 'Complete';}
    update ProductstoUpdate;
    }

 

All Answers

Suresh RaghuramSuresh Raghuram

if the status will become complete on the project (object which is seperate from opportunity other than just a field ) and you are expecting the field update on the opportunity object that doesnt work ,

 

The reason is workflows did not support the crosss functional objects.

 

If above assumptions or the guess is right then you should write a trigger

 

If this answers your question make this as solution

JitendraJitendra

Hi,

 

This can be easily done with trigger.

 

Write "after Insert" trigger and check whether the status of Opportunity is 'Won' or 'Lost'. If condition meet then get list of all child / related project and update there status also.

cambart14cambart14

Jitendra, you're comment has been most helpful, although I sitll need a bit more direction and help with the trigger.

 

I have outline below what I want the trigger to do, but I'm not sure where to start to have it get a list of all child/related projects.

 

trigger closeChildObjects on Opportunity (after insert) {

    //If Opportuny Stage = "Won" or "Lost" execute below code, else {}
    if(OR(stage__c="Won",stage__c="Lost") 
    {
        //Get all child Projects (Project__c) objects

        //Change child Projects status to 'Complete'
    ; }

}

 Any help on this would be great, thank you!

WEN JIEWEN JIE

Hi,

 

If your opportunity is marked as "Won" or "Lost", when this opportunity created, you can create a "after insert" trigger.

 

trigger myTirgger on Opportunity (after insert) {
    //your code
}

 

If your opportunity has another status when it created, then after some operates, you change the opportunity from its origional status to "Won" or "Lost", in this scenario, craete a "after update"

 

trigger myTirgger2 on Opportunity (after update) {
    //your code
}

 

Thank you!

 

 

cambart14cambart14

I have written a trigger to try and update the related custom object, but I keep getting this error Error: Initial term of field expression must be a concrete SObject: Id at line 8 column 6.  My code is below:

 

trigger closeRelatedItems on Opportunity (after insert, after update) {

    Set<ID> StageNames = new Set<ID>();
    for(Opportunity o: Trigger.new)
        StageNames.add(o.id);
    List<Project__c> ProductsToUpdate = new List<Project__c> {[SELECT ID, Status__c  FROM Project__c WHERE Status__c = : StageNames]};
    for(ID ol: ProductsToUpdate)
    {ol.Status__c = 'Complete';}
    update ProductstoUpdate;
    }

 

WEN JIEWEN JIE

Hi,

 

As your code, the list ProductsToUpdate's type is Project__c,so if you want to loop this list, you need change ol type to Project__c.

 

for(Project__c ol: ProductsToUpdate)
    {ol.Status__c = 'Complete';}
    update ProductstoUpdate;
}

 

 

JitendraJitendra

Try this :

 

trigger closeRelatedItems on Opportunity (after insert, after update) {

    Set<ID> StageNames = new Set<ID>();
    for(Opportunity o: Trigger.new)
        StageNames.add(o.id);
    List<Project__c> ProductsToUpdate = [SELECT ID, Status__c  FROM Project__c WHERE Status__c = : StageNames];
    for(Project__c ol: ProductsToUpdate)
    {ol.Status__c = 'Complete';}
    update ProductstoUpdate;
    }

 

cambart14cambart14

Jitendra and WEN JIE,

 

Your suggestions got rid of the error message, but the trigger still doesn't seem to updated the related Project objects.  I have tried editing the Opportunity in several different ways, but the Project status never updates.  I'm not sure what is missing...

WEN JIEWEN JIE

Hi,

 

I think you can add some system.debug in your trigger then can see some values in Debug Logs and check the detail.

 

trigger closeRelatedItems on Opportunity (after insert, after update) {

    Set<ID> StageNames = new Set<ID>();
    for(Opportunity o: Trigger.new){
        StageNames.add(o.id);
        System.debug('=====id===='+o.id);
    }
    List<Project__c> ProductsToUpdate = [SELECT ID, Status__c  FROM Project__c WHERE Status__c = : StageNames];
    //before change
    System.debug('===Project==='+ProductsToUpdate);
    for(Project__c ol: ProductsToUpdate)
    {ol.Status__c = 'Complete';}
    //after change
    System.debug('===Project==='+ProductsToUpdate);
    update ProductstoUpdate;
}

 Actually ,I don't think you need to use Set. And your Status__c is the opportunity id??? Please check your SOQL.

 

Thank you!

cambart14cambart14

Thanks for your suggestions JIE.  I am new to programming in Salesforce, so I'm sure there are several big mistakes in my code.  I have changed my SOQL, but still not quite sure if it right.

 

I have found another example of updating related child fields (see revised code below).  I'm wondering if this would be more effective at trying to accomplish my task?

 

trigger closeRelatedItems on Opportunity (after insert, after update) {

            Set<Id> StageNames = new Set<Id>();
            //select related child Projects
            Map<ID, Project__c> projectrecords = new Map<ID, Project__c>([SELECT ID, Status__c from Project__c WHERE ID IN: StageNames]);
            System.debug('===Project==='+projectrecords);
        
        //update related child Projects    
        for (Opportunity o : Trigger.new) {
            for(Project__c c : projectrecords.values()){
                c.Status__c = 'Complete';
                System.debug('===Project==='+projectrecords);
                update c;
        }
    } 
}

 Thanks again!

JitendraJitendra

Hi, 

Here your code :

 

trigger closeRelatedItems on Opportunity (after insert, after update) {

    Set<ID> oppIds = new Set<ID>();
    for(Opportunity o: Trigger.new)
	{
		if(o.stage__c="Won" || o.stage__c="Lost")
		{
			oppIds.add(o.id);
		}
	}
	
    //replace field "parentOpportunity__c " with actual field name which is lookup to opportunity
    List<Project__c> ProductsToUpdate = [SELECT ID, Status__c  FROM Project__c WHERE parentOpportunity__c IN : oppIds];
    for(Project__c ol: ProductsToUpdate)
    {ol.Status__c = 'Complete';}
    update ProductstoUpdate;
    }

 

This was selected as the best answer
cambart14cambart14

Jitendra!  That worked great, thank you!  I made a few revisions to the code (see below), but other than that it worked great.

 

trigger closeRelatedItems on Opportunity (after insert, after update) {

    Set<ID> oppIds = new Set<ID>();
    for(Opportunity o: Trigger.new)
    {
        if(o.StageName=='Won' || o.StageName=='Lost')
        {
            oppIds.add(o.id);
        }
    }
    
    List<Project__c> ProductsToUpdate = [SELECT ID, Status__c  FROM Project__c WHERE Related_Opportunity__c IN : oppIds];
    for(Project__c ol: ProductsToUpdate)
    {ol.Status__c = 'Complete';}
    update ProductstoUpdate;
    }

 

WEN JIEWEN JIE

It's great! I also get useful info from your SOQL.