You need to sign in to do that
Don't have an account?
Trigger a Chatter Post when an Opportunity is won
Hello Everyone,
I am an APEX newbie trying to create a trigger that posts when an Opp is won. I have no other requirements besides that the when an Opportunity is updated to the won stage, it posts a pedesigned message to a specific Chatter Group. I took the code from another post (https://developer.salesforce.com/forums/ForumsMain?id=906F00000009AFJIA2) and tried to modify it to do just that but I am running into a problem in the IDE at the "for" line, with the error stating "Save error: Loop must iterate over collection type: Boolen". I tried to add an else statement to break and exit the loop but that gave me a bracket error. Am I totally off base here? Should I pulling a list first for the function to iterate over? Any help would be much appreciated! Thanks!
trigger ChatterPostWonOpp on Opportunity (after update) {
String status;
String OppAccName;
String OppOwnerName;
FeedItem post = new FeedItem();
for(Opportunity o : Trigger.isupdate) {
if(o.IsWon == true ) //This will be executed on new record insertion when Opp is won
for (Opportunity oppty : [SELECT Account.Name, Owner.Name FROM Opportunity])
{
OppAccName = oppty.Account.Name;
OppOwnerName = oppty.Owner.Name;
}
status = OppOwnerName + ' just won ' + OppAccName + ' for ' + o.Amount + '!';
post.ParentId = '0F9g00000008b7c';
post.Title = o.Name;
post.Body = status;
insert post;
}
}
I am an APEX newbie trying to create a trigger that posts when an Opp is won. I have no other requirements besides that the when an Opportunity is updated to the won stage, it posts a pedesigned message to a specific Chatter Group. I took the code from another post (https://developer.salesforce.com/forums/ForumsMain?id=906F00000009AFJIA2) and tried to modify it to do just that but I am running into a problem in the IDE at the "for" line, with the error stating "Save error: Loop must iterate over collection type: Boolen". I tried to add an else statement to break and exit the loop but that gave me a bracket error. Am I totally off base here? Should I pulling a list first for the function to iterate over? Any help would be much appreciated! Thanks!
trigger ChatterPostWonOpp on Opportunity (after update) {
String status;
String OppAccName;
String OppOwnerName;
FeedItem post = new FeedItem();
for(Opportunity o : Trigger.isupdate) {
if(o.IsWon == true ) //This will be executed on new record insertion when Opp is won
for (Opportunity oppty : [SELECT Account.Name, Owner.Name FROM Opportunity])
{
OppAccName = oppty.Account.Name;
OppOwnerName = oppty.Owner.Name;
}
status = OppOwnerName + ' just won ' + OppAccName + ' for ' + o.Amount + '!';
post.ParentId = '0F9g00000008b7c';
post.Title = o.Name;
post.Body = status;
insert post;
}
}
You also should not hardcode the chatter group ID, since this value will change when you deploy your code to production. You can use a query to get that information as well.
Putting all of this together, your code might look something like this:
trigger ChatterPostWonOpp on Opportunity (after update) {
List<FeedItem> posts = new List<FeedItem>();
List<Opportunity> updatedOpps = [SELECT Name, Account.Name, Owner.Name, Amount FROM Opportunity WHERE Id IN :Trigger.newMap.keySet() AND IsWon = true];
CollaborationGroup chatterGroup = [SELECT Id FROM CollaborationGroup WHERE Name = 'ChatterGroupName' LIMIT 1];
for (Opportunity opp : updatedOpps) {
String status = opp.Owner.Name + ' just won ' + opp.Account.Name + ' for ' + opp.Amount + '!';
FeedItem post = new FeedItem(
ParentId = chatterGroup.Id,
Title = opp.Name,
Body = status
);
posts.add(post);
}
insert posts;
}
All Answers
You also should not hardcode the chatter group ID, since this value will change when you deploy your code to production. You can use a query to get that information as well.
Putting all of this together, your code might look something like this:
trigger ChatterPostWonOpp on Opportunity (after update) {
List<FeedItem> posts = new List<FeedItem>();
List<Opportunity> updatedOpps = [SELECT Name, Account.Name, Owner.Name, Amount FROM Opportunity WHERE Id IN :Trigger.newMap.keySet() AND IsWon = true];
CollaborationGroup chatterGroup = [SELECT Id FROM CollaborationGroup WHERE Name = 'ChatterGroupName' LIMIT 1];
for (Opportunity opp : updatedOpps) {
String status = opp.Owner.Name + ' just won ' + opp.Account.Name + ' for ' + opp.Amount + '!';
FeedItem post = new FeedItem(
ParentId = chatterGroup.Id,
Title = opp.Name,
Body = status
);
posts.add(post);
}
insert posts;
}
seems to me a problem at line number 8 of your trigger code i.e. for(Opportunity o : Trigger.isupdate)
Trigger.isupdate retuns a boolean value and you can't iterate over a boolean value. Use 'Trigger.old' or 'Trigger.new' instead.
You can use any one of Trigger.old or Trigger.new depending on your logic. Trigger.old contains the object prior to the updation whereas new have updated object. In my view, in your case trigger.new will do the trick. but i am not sure, so, try yourself which one is working for you.
Regards,
Sushil.
Thank so much for the help and quick response! I am going to work on this in the afternoon (EST) and I will let you know how I make out.
Thank you for your input! I think I will need the Trigger.new because I want the iteration to happen after the status has been changed. ! am working on it now. I will let you know what I find. Thanks!
I want to thank you both again for your help.
I took both of your suggestions and tried to make them work. Testing both helped me understand the two different approaches and will help me in the long run learn more about APEX. I think I will probably end up using Cheyne's approach because it respects the governor limits and this is something I was warned about in ADM231. However, when I tried Cheyne's approach, I got a "String Error". This is my fault because I didn't change one of the fields in the copied formula. What I posted above is checking the IsWon field which I assume is a boolean field in the user's Org who posted this formula to the forum. The field I want to check is called Stage Name and is a picklist field. Also, rather than checking whether it is true or false, I want to know if it contains the word 'Won'. I found the contains function and replaced it, I think correctly, in the code but now I am getting a "Unexpected token error" on the word 'Won'. I am thinking this maybe has something to do with it being a String and I need to somehow convert the value to a String? I did some searching and found that you can use something like the following to convert it.
contact c = new contact();
.....
.....
String str = c.multiPickList__c;
if (str.contains('TEXTVALUE') {}
.......
This would work I think in the original formula but not in the one suggested by Cheyne because there is no more 'if' statement so I am stuck as to where I should go from here. Any ideas?
trigger ChatterPostWonOpp2 on Opportunity (after update) {
List<FeedItem> posts = new List<FeedItem>();
List<Opportunity> updatedOpps = [SELECT Name, Account.Name, Owner.Name, Amount FROM Opportunity WHERE Id IN :Trigger.newMap.keySet() AND stagename.contains('Won')];
CollaborationGroup chatterGroup = [SELECT Id FROM CollaborationGroup WHERE Name = 'OURCHATTERGROUNAME' LIMIT 1];
for (Opportunity opp : updatedOpps) {
String status = opp.Owner.Name + ' just won ' + opp.Account.Name + ' for ' + opp.Amount + '!';
FeedItem post = new FeedItem(
ParentId = chatterGroup.Id,
Title = opp.Name,
Body = status
);
posts.add(post);
}
insert posts;
}
AND stagename LIKE '%Won%'
You can find details on the different types of operators you can use in SOQL queries at http://www.salesforce.com/us/developer/docs/dbcom_soql_sosl/Content/sforce_api_calls_soql_select_comparisonoperators.htm (http://www.salesforce.com/us/developer/docs/dbcom_soql_sosl/Content/sforce_api_calls_soql_select_comparisonoperators.htm" target="_blank)
for (Opportunity opp : updatedOpps) {
//This ensures that the StageName actually changed during this update
if (trigger.oldMap.get(opp.Id).StageName != trigger.newMap.get(opp.Id).StageName) {
//create your chatter post
}
}
I changed the code around a bit so that it is looking at the Forecast Category Name instead of the Stage. I did this becuase there are multiple "Won" Stages but they are all attached to the "Closed" Forecat Category Name. I found though that it is still posting when I move the Opportunity in and out of different "Won" Stages. It shouldn't be posting becuase the Forecst Category Name of "Closed" should not be changing. Did I do something wrong? Here is my current code:
trigger ChatterPostWonOpp2 on Opportunity (after update) {
List<FeedItem> posts = new List<FeedItem>();
List<Opportunity> updatedOpps = [SELECT Name, Account.Name, Owner.Name, Amount FROM Opportunity WHERE Id IN :Trigger.newMap.keySet() AND forecastcategoryname = 'Closed' ];
CollaborationGroup chatterGroup = [SELECT Id FROM CollaborationGroup WHERE Name = 'All Metso MAC' LIMIT 1];
for (Opportunity opp : updatedOpps) {
if (trigger.oldMap.get(opp.Id).ForecastCategoryName != trigger.newMap.get(opp.Id).ForecastCategoryName) {
String status = opp.Owner.Name + ' just won ' + opp.Name + '!' + ' Nice Job!';
FeedItem post = new FeedItem(
ParentId = chatterGroup.Id,
Title = opp.Name,
Body = status
);
posts.add(post);
}
insert posts;
}
Thanks again for all your help on this. I am really learning a lot from you.
for (Opportunity opp : updatedOpps) {
system.debug('Old ForecastCategoryName ==> ' + trigger.oldMap.get(opp.Id).ForecastCategoryName);
system.debug('New ForecastCategoryName ==> ' + trigger.newMap.get(opp.Id).ForecastCategoryName);
//This is checking if the values are different: i.e. the value was changed during this update
if (trigger.oldMap.get(opp.Id).ForecastCategoryName != trigger.newMap.get(opp.Id).ForecastCategoryName) {
//create your post
}
}
Try running it like that and then check your debug log to see what values it is outputting.
I played around with the debugs and test coding a little but I just don't think I have thorough understanding of testing yet. I am going to work with the APEX developer guide and see if I can get this worked out in the next few weeks. I have been pulled onto a couple other projects too so I will post an update as soon as I have one. Thanks again for all your help. You rock!