4

I have a trigger that updates/ inserts opportunities when the account is created. This was implemented by a third party. Now I would like to update the opportunities to Cancelled when the Account status= 'Cancelled'.

I have tried this via workflow rules and field update but this did not work. Below is my attempt to create the trigger, but I think its terribly wrong. Help would be greatly appreciated.

trigger updateopporutnites on Account (after update) {

Set<String> Account=new Set<String>();
for(Account ac : Trigger.new)
{
if(ac.Status__c=='Cancelled')
Account.add(ac.OpportunityId);
}
for(Opportunity opp : [select id, StageName from Opportunity where id in: Account])
{
opp.StageName='Closed - Cancelled';
update opp;
}
}
  • In the other question you had, one outstanding question was whether or not your record type was equal to "Production"? In this trigger you are not looking at the record type. Did you try the workflow rule without the record type in the criteria? – Jenny B Oct 6 '14 at 18:25
  • Yes I did and it didn't work. I can add the record type later. I just want to figure out why the workflow rule wasn't working. I found a forum which stated that it should be setup as a trigger as workflow rules have a lot of limitations. Hence I am here. I know this trigger has an error. Not sure what I'm missing or if this is correct. – devista Oct 6 '14 at 18:41
  • Do you have access to the 3rd party trigger? You might be better off taking a look at that and either adding your logic there or seeing what might be preventing your workflow rule from working properly. Also, did you check to see if there are any other workflow rules associated with opportunities that could be overriding your new workflow rule? You want to be careful about having multiple triggers especially if they are for the same transaction, there is no guarantee in the order the the triggers will fire. – Jenny B Oct 6 '14 at 18:48
  • @JennyB This cannot be achieved with a workflow rule as it needs to update child objects on the object it is triggered from. – Alex Tennant Oct 6 '14 at 18:53
  • @AlexTennant - His original question had the workflow rule running when the opportunity was created/edited. salesforce.stackexchange.com/questions/51359/… - which I guess is why what he was looking for didn't work. I understood the problem to be when these oppty records were generated, not when the account was edited. – Jenny B Oct 6 '14 at 18:56
4

You're very, very close. What you need to do is gather up the Account Ids and query for the Opportunities using them since each Account could have multiple Opportunities.

You also need to remove your DML from the loop to bulkify your trigger.

 trigger updateopportunities on Account(after update) 
{
    Set<Id> accountIds = new Set<Id>();

    for(Account ac : Trigger.new)
    {
         if(ac.Status__c=='Cancelled')
              accounIds.add(ac.Id);
    }

     List<Opportunity> oppsToUpdate = new List<Opportunity>();

     for(Opportunity opp : [select id, StageName from Opportunity where AccountId in: accountIds])
     {
          opp.StageName='Closed - Cancelled';
          oppsToUpdate.add(opp);
     }

     update oppsToUpdate;
}
  • Thank you so much :). I had been struggling with this for a while now. – devista Oct 6 '14 at 19:17
  • Would you be able to tell me how I would create test units for this? Would It be example creating an account and then calling this trigger? I am new to creating triggers so not really entirely sure how I would do that. If you could let me know that would be immensely appreciated. – devista Oct 13 '14 at 22:00
3

Here's another version of the trigger with more guards in it so that it only does work when it needs to - changes to other fields on Account won't consume queries or DML.

The reason to take extra care here is that the Account object can be shared by many apps and customisations in an org, so the trigger logic can pile up. So best to add as little overhead as possible in each trigger by being as selective as possible.

trigger updateopportunities on Account(after update)  {

    Set<Id> accountIds = new Set<Id>();
    for (Account acc : Trigger.new) {
         Account old = Trigger.oldMap.get(acc.Id);
         if (acc.Status__c == 'Cancelled' && acc.Status__c != old.Status__c) {
             accountIds.add(acc.Id);
         }
    }

    if (!accountIds.isEmpty()) {
        List<Opportunity> opps = [
                select Id, StageName
                from Opportunity
                where AccountId in: accountIds
                and StageName != 'Closed - Cancelled'
                ];
        if (!opps.isEmpty()) {
            for (Opportunity opp : opps) {
                opp.StageName = 'Closed - Cancelled';
            }
            update opps;
        }
    }
}
  • There is a syntax error on this on line 17 '])' – devista Oct 6 '14 at 20:08
  • Sorry question why are we not looping through the opportunities here?? – devista Oct 6 '14 at 20:09
  • @dev_1_million Yep I've fixed the syntax error - sorry about that. There is a loop over the opportunities on line 19. This code is fetching the whole list first and then looping over them because the whole lot need to be in memory to update near the end anyway. – Keith C Oct 6 '14 at 21:41
  • thank you so much. I had another question. Currently the opportunity Owners are notified based on the Account Location via email. How can I have notifications sent after when the opportunites are cancelled. – devista Oct 7 '14 at 12:56

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.