You need to sign in to do that
Don't have an account?
Duplicate Chatter Posts - please help
Hi,
I have a trigger that posts a notification to a Chatter Group when an opportunity is Closed Won. The trigger works, however it always posts TWO duplicate posts at the exact same time. Below is my code....thoughts on how to fix this? Thanks!
trigger AddClosedWontoChatter on Opportunity (after update) {
list<FeedItem> fplist = new list<FeedItem>();
String opportunityPrefix = Opportunity.SobjectType.getDescribe().getKeyPrefix();
for(Opportunity o : trigger.new){
FeedItem fpost= new FeedItem();
if(o.StageName == 'Closed Won' )
{
fpost.type = 'LinkPost';
fpost.parentid = '0F930000000CbQL';
fpost.Body = 'RTB Alert! Your teammate just Closed Won the $' + o.Invoice_Closed_Won__c + ' opportunity -- ' + o.Name
+ '\nReason Won Details: ' + o.Reason_Won_Lost_Additional_Details__c;
fpost.linkUrl = 'https://na1.salesforce.com/' + o.id;
fpost.title = o.Name + ' - ' + o.Invoice_Closed_Won__c;
fplist.add(fpost);
}
}
if(fplist.size()!=0){
try{
insert fplist;
}
catch(system.exception e){
system.debug('Error: '+e);
}
}
So, I ended up figuring this out and wanted to post the resolution....It was actually a simple fix, but tricky to discover and I wouldn't have done so without some fabulous tips from Ashish in Premiere support = #rockstar!
Because we have workflow rules that update opportunities, that was what was triggering the double post. To work around this, I added a class:
global class test1{
public static boolean flag=true;
}
Then, reference that class in the trigger so it doesn't post twice:
if(test1.flag == true){
test1.flag=false;
The full code of the trigger is:
trigger AddClosedWontoChatter on Opportunity (after update)
{
//Setup the Feeditem array of items to post to Chatter
list<FeedItem> fplist = new list<FeedItem>();
//Setup the array to hold the ids to Iterate through
Set<Id> pbeIds = new Set<Id>();
//Iterate through the Opp
for (Opportunity o : Trigger.new)
{
// Create individual post
pbeIds.add(o.Id);
}
//Setup APEX MAP Arrays to get the required data from the Pricebook and Opportunity
Map<Id, Opportunity> Opp = new Map<Id, Opportunity>([select Account.Name, Account.ID, Owner.Name, Owner.Id, Owner.UserRoleId from Opportunity where id in :pbeIds]);
//Iterate through the line items once again to add the data to the Chatter Object
for (Opportunity o : Trigger.new)
{
Opportunity oldo = Trigger.oldMap.get (o.id);
//If the part outcomes are different, let's add to the chatter feed
if(o.StageName != oldo.StageName && o.StageName == 'Closed Won' && o.Account.Id != '0013000000GJRrU'
&& ((o.Invoice_Closed_Won__c > 79999 && (o.Type == 'Affiliated New' || o.Type == 'Renewal'))
|| (o.Invoice_Closed_Won__c > 19999 && (o.Type == 'SMB - Affiliated New' || o.Type == 'SMB - Renewal' || o.Type == 'SMB'))
|| (o.Invoice_Closed_Won__c > 29999 && o.Type == 'New')
|| (o.Invoice_Closed_Won__c > 5999 && o.Owner.UserRoleId == '00E30000001U9dG' ))
)
{
if(test1.flag == true){
test1.flag=false;
FeedItem fpost= new FeedItem();
fpost.parentId = '0F930000000CbQL';
fpost.createdbyid = UserInfo.getUserId();
fpost.Type = 'LinkPost';
fpost.Title = o.Name + ' - $' + o.Invoice_Closed_Won__c;
fpost.Body = 'has Closed Won the following $' + o.Invoice_Closed_Won__c + ' opportunity on Account: ' +opp.get(o.Id).Account.Name+ '. Congrats, ' + opp.get(o.Id).Owner.Name + '!'
+ '\n*Application: ' + o.Application__c
+ '\n*Reason Won Details: ' + o.Reason_Won_Lost_Additional_Details__c;
String id = String.valueOf(o.Id).substring(0,15);
fpost.LinkURL = 'https://na1.salesforce.com/' + o.id;
fplist.add(fpost);
}
}
}
//if the post is empty, don't try and post it to Chatter
if(!fplist.isEmpty())
{
insert fplist;
}
The test class is:
@isTest
public with sharing class ChatterClosedWonOppTests {
/*
* Test the AddClosedWontoChatter trigger which inserts chatter feed posts whenever an opportunity is closed won at a certain value
*/
public static testMethod void testAddClosedWontoChatter() {
Profile p = [select id from profile where name='Standard User'];
User u = new User(alias = 'test123', email='test123@noemail.com',
emailencodingkey='UTF-8', languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id, country='United States',
FirstName='Test',
LastName='User',
timezonesidkey='America/Los_Angeles', username='test123@noemail.com');
insert u;
CollaborationGroup c = new CollaborationGroup(name='Test Group',CollaborationType='Public');
insert c;
//create the test opportunity
Opportunity testOpp = new Opportunity( Name = 'My Test Opp',
StageName = '2 - Discovery',
Owner = u,
Type = 'SMB',
Invoice_Forecast__c = 25000,
CloseDate = System.today());
insert testOpp;
//Since it is an after update trigger, update the opp that was just inserted.
testopp.StageName = 'Closed Won';
testopp.Reason_Won__c = 'Price';
testopp.Competition__c = 'None';
testopp.Application__c = 'Compliance';
update testopp; // this statement will fire the trigger
// Get the feed post that was supposed to be created based on
// closing the opportunity
// List <FeedItem> posts = [SELECT id
// FROM FeedItem
// WHERE ParentId = :c.Id];
// System.assertEquals(1,posts.size());
// List<CollaborationGroupFeed> posts = [SELECT Id, Type
// FROM CollaborationGroupFeed
// WHERE ParentId = :c.id];
// System.assertEquals(1, posts.size());
}
All Answers
You need to check the oldValue as well, and only post if its not Closed Won, otherwise this is going to post an entry everytime the oportunity is saved once it reaches closed won.
Thanks, I tried this, however it still appears to be posting duplicates:
if(o.StageName == 'Closed Won' && trigger.oldMap.get(o.id).StageName != 'Closed Won')
Thoughts?
So, I ended up figuring this out and wanted to post the resolution....It was actually a simple fix, but tricky to discover and I wouldn't have done so without some fabulous tips from Ashish in Premiere support = #rockstar!
Because we have workflow rules that update opportunities, that was what was triggering the double post. To work around this, I added a class:
global class test1{
public static boolean flag=true;
}
Then, reference that class in the trigger so it doesn't post twice:
if(test1.flag == true){
test1.flag=false;
The full code of the trigger is:
trigger AddClosedWontoChatter on Opportunity (after update)
{
//Setup the Feeditem array of items to post to Chatter
list<FeedItem> fplist = new list<FeedItem>();
//Setup the array to hold the ids to Iterate through
Set<Id> pbeIds = new Set<Id>();
//Iterate through the Opp
for (Opportunity o : Trigger.new)
{
// Create individual post
pbeIds.add(o.Id);
}
//Setup APEX MAP Arrays to get the required data from the Pricebook and Opportunity
Map<Id, Opportunity> Opp = new Map<Id, Opportunity>([select Account.Name, Account.ID, Owner.Name, Owner.Id, Owner.UserRoleId from Opportunity where id in :pbeIds]);
//Iterate through the line items once again to add the data to the Chatter Object
for (Opportunity o : Trigger.new)
{
Opportunity oldo = Trigger.oldMap.get (o.id);
//If the part outcomes are different, let's add to the chatter feed
if(o.StageName != oldo.StageName && o.StageName == 'Closed Won' && o.Account.Id != '0013000000GJRrU'
&& ((o.Invoice_Closed_Won__c > 79999 && (o.Type == 'Affiliated New' || o.Type == 'Renewal'))
|| (o.Invoice_Closed_Won__c > 19999 && (o.Type == 'SMB - Affiliated New' || o.Type == 'SMB - Renewal' || o.Type == 'SMB'))
|| (o.Invoice_Closed_Won__c > 29999 && o.Type == 'New')
|| (o.Invoice_Closed_Won__c > 5999 && o.Owner.UserRoleId == '00E30000001U9dG' ))
)
{
if(test1.flag == true){
test1.flag=false;
FeedItem fpost= new FeedItem();
fpost.parentId = '0F930000000CbQL';
fpost.createdbyid = UserInfo.getUserId();
fpost.Type = 'LinkPost';
fpost.Title = o.Name + ' - $' + o.Invoice_Closed_Won__c;
fpost.Body = 'has Closed Won the following $' + o.Invoice_Closed_Won__c + ' opportunity on Account: ' +opp.get(o.Id).Account.Name+ '. Congrats, ' + opp.get(o.Id).Owner.Name + '!'
+ '\n*Application: ' + o.Application__c
+ '\n*Reason Won Details: ' + o.Reason_Won_Lost_Additional_Details__c;
String id = String.valueOf(o.Id).substring(0,15);
fpost.LinkURL = 'https://na1.salesforce.com/' + o.id;
fplist.add(fpost);
}
}
}
//if the post is empty, don't try and post it to Chatter
if(!fplist.isEmpty())
{
insert fplist;
}
The test class is:
@isTest
public with sharing class ChatterClosedWonOppTests {
/*
* Test the AddClosedWontoChatter trigger which inserts chatter feed posts whenever an opportunity is closed won at a certain value
*/
public static testMethod void testAddClosedWontoChatter() {
Profile p = [select id from profile where name='Standard User'];
User u = new User(alias = 'test123', email='test123@noemail.com',
emailencodingkey='UTF-8', languagelocalekey='en_US',
localesidkey='en_US', profileid = p.Id, country='United States',
FirstName='Test',
LastName='User',
timezonesidkey='America/Los_Angeles', username='test123@noemail.com');
insert u;
CollaborationGroup c = new CollaborationGroup(name='Test Group',CollaborationType='Public');
insert c;
//create the test opportunity
Opportunity testOpp = new Opportunity( Name = 'My Test Opp',
StageName = '2 - Discovery',
Owner = u,
Type = 'SMB',
Invoice_Forecast__c = 25000,
CloseDate = System.today());
insert testOpp;
//Since it is an after update trigger, update the opp that was just inserted.
testopp.StageName = 'Closed Won';
testopp.Reason_Won__c = 'Price';
testopp.Competition__c = 'None';
testopp.Application__c = 'Compliance';
update testopp; // this statement will fire the trigger
// Get the feed post that was supposed to be created based on
// closing the opportunity
// List <FeedItem> posts = [SELECT id
// FROM FeedItem
// WHERE ParentId = :c.Id];
// System.assertEquals(1,posts.size());
// List<CollaborationGroupFeed> posts = [SELECT Id, Type
// FROM CollaborationGroupFeed
// WHERE ParentId = :c.id];
// System.assertEquals(1, posts.size());
}
Thanks for the workaround, Chris. I was facing the same issue and found this workaround.
Generally a trigger gets executed only once and hence we expect the post to happen only once.
Can someone from SF explain as to why is this happening?
And without this workaround, is there anything else we should take care so that it does not cause a double post?
My organization is asking for this same functionality, but I don't know Apex code at all. What I am having trouble identifying is where the specific Chatter feed is located in this code, and also how I would adjust it to accomodate opportunities over $1M.
Can you help?
Thanks, Erik