You need to sign in to do that
Don't have an account?
Copy Contact Roles from Opportunity to Clone Opportunity?
I've written a trigger that duplicates an opportunity when we change its status to "Closed-Won." The idea is that every time we close an opportunity, we want to create a follow-up opportunity for pursuing that client again. My trigger makes a clone of the opportunity, adds some new products and schedule items, sets the status to discovery, and a couple of other minor things. As of right now, the trigger doesn't actually copy any objects associated with opportunity. Ideally, if there's a way to do this, I want to copy all of the existing Contact Roles from the closed Opp to the new one. Here's my code...let me know if you have any questions about it or need to know anything about our setup.
Thanks!
trigger Create_followup on Opportunity (before update, after insert) {
Pricebook2 standardBook = [SELECT Id FROM Pricebook2 WHERE Name = :'Ambition'];//Create an instance of the standard pricebook
if(Trigger.isUpdate){
List<Opportunity> listOppor = new List<Opportunity>();
for (Opportunity o: Trigger.new){
if (o.StageName == 'Closed Won' && o.Stage_Change__c == false && o.Is_Clone__c == false){
Opportunity oppNew = o.clone();
oppNew.Name = oppNew.Name + ' - Annual ' + o.CloseDate.year();
if(o.Renewal_Date__c != null){
oppNew.Renewal_Date__c = o.Renewal_Date__c.addYears(1);
oppNew.CloseDate = o.Renewal_Date__c.addYears(1);}
oppNew.StageName = 'Discovery';
oppNew.Probability = 25;
oppNew.Pricebook2Id = standardBook.Id;//associate the standard pricebook with this opportunity
oppNew.Is_Clone__c = true;
listOppor.add(oppNew);
o.Stage_Change__c = true;
}
}//end of for loop
if(listOppor.size() > 0){
insert listOppor;
}
}
if(trigger.isInsert){
try{
OpportunityLineItem[] lines = new OpportunityLineItem[0];
PricebookEntry entry = [SELECT Id, UnitPrice FROM PricebookEntry WHERE Pricebook2Id = :standardBook.Id AND Product2.ProductCode = 'ENTERPRISE_ANNUAL_UPFRONT'];
List<Event> eventList = new List<Event>();
//List<Note> noteList = new List<Note>();
for(Opportunity o: Trigger.new){
if(o.Is_Clone__c == true){
//noteList.add(new Note(ParentId=o.id,Title='Matt is the Apex_God',Body='Matt is the Apex_God',isPrivate=false));
lines.add(new OpportunityLineItem(PricebookEntryId=entry.Id, OpportunityId=o.Id, UnitPrice=entry.UnitPrice, Quantity=1));
if(o.Renewal_Date__c != null){
DateTime myDateTime = o.Renewal_Date__c.addMonths(-10);
eventList.add(new Event(whatid=o.id,startdatetime=myDateTime,subject='Account Management Follow-Up', EndDateTime=myDateTime, IsAllDayEvent=true));
eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(2),subject='Account Management Follow-Up', EndDateTime=myDateTime.addMonths(2), IsAllDayEvent=true));
eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(4),subject='Account Management Follow-Up', EndDateTime=myDateTime.addMonths(4), IsAllDayEvent=true));
eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(6),subject='Account Management Follow-Up', EndDateTime=myDateTime.addMonths(6), IsAllDayEvent=true));
eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(8),subject='Account Management Follow-Up', EndDateTime=myDateTime.addMonths(8), IsAllDayEvent=true));
eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(10),subject='Account Management Follow-Up', EndDateTime=myDateTime.addMonths(10), IsAllDayEvent=true));
eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(10),subject='Renewal',EndDateTime=myDateTime.addMonths(10), IsAllDayEvent=true));
eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(9),subject='Sales Contract Follow-Up',EndDateTime=myDateTime.addMonths(9), IsAllDayEvent=true));
}//end of if
}
}
insert lines;
insert eventList;
//insert noteList;
}
catch(Exception e){
}
}
}
Thanks!
trigger Create_followup on Opportunity (before update, after insert) {
Pricebook2 standardBook = [SELECT Id FROM Pricebook2 WHERE Name = :'Ambition'];//Create an instance of the standard pricebook
if(Trigger.isUpdate){
List<Opportunity> listOppor = new List<Opportunity>();
for (Opportunity o: Trigger.new){
if (o.StageName == 'Closed Won' && o.Stage_Change__c == false && o.Is_Clone__c == false){
Opportunity oppNew = o.clone();
oppNew.Name = oppNew.Name + ' - Annual ' + o.CloseDate.year();
if(o.Renewal_Date__c != null){
oppNew.Renewal_Date__c = o.Renewal_Date__c.addYears(1);
oppNew.CloseDate = o.Renewal_Date__c.addYears(1);}
oppNew.StageName = 'Discovery';
oppNew.Probability = 25;
oppNew.Pricebook2Id = standardBook.Id;//associate the standard pricebook with this opportunity
oppNew.Is_Clone__c = true;
listOppor.add(oppNew);
o.Stage_Change__c = true;
}
}//end of for loop
if(listOppor.size() > 0){
insert listOppor;
}
}
if(trigger.isInsert){
try{
OpportunityLineItem[] lines = new OpportunityLineItem[0];
PricebookEntry entry = [SELECT Id, UnitPrice FROM PricebookEntry WHERE Pricebook2Id = :standardBook.Id AND Product2.ProductCode = 'ENTERPRISE_ANNUAL_UPFRONT'];
List<Event> eventList = new List<Event>();
//List<Note> noteList = new List<Note>();
for(Opportunity o: Trigger.new){
if(o.Is_Clone__c == true){
//noteList.add(new Note(ParentId=o.id,Title='Matt is the Apex_God',Body='Matt is the Apex_God',isPrivate=false));
lines.add(new OpportunityLineItem(PricebookEntryId=entry.Id, OpportunityId=o.Id, UnitPrice=entry.UnitPrice, Quantity=1));
if(o.Renewal_Date__c != null){
DateTime myDateTime = o.Renewal_Date__c.addMonths(-10);
eventList.add(new Event(whatid=o.id,startdatetime=myDateTime,subject='Account Management Follow-Up', EndDateTime=myDateTime, IsAllDayEvent=true));
eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(2),subject='Account Management Follow-Up', EndDateTime=myDateTime.addMonths(2), IsAllDayEvent=true));
eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(4),subject='Account Management Follow-Up', EndDateTime=myDateTime.addMonths(4), IsAllDayEvent=true));
eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(6),subject='Account Management Follow-Up', EndDateTime=myDateTime.addMonths(6), IsAllDayEvent=true));
eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(8),subject='Account Management Follow-Up', EndDateTime=myDateTime.addMonths(8), IsAllDayEvent=true));
eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(10),subject='Account Management Follow-Up', EndDateTime=myDateTime.addMonths(10), IsAllDayEvent=true));
eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(10),subject='Renewal',EndDateTime=myDateTime.addMonths(10), IsAllDayEvent=true));
eventList.add(new Event(whatid=o.id,startdatetime=myDateTime.addMonths(9),subject='Sales Contract Follow-Up',EndDateTime=myDateTime.addMonths(9), IsAllDayEvent=true));
}//end of if
}
}
insert lines;
insert eventList;
//insert noteList;
}
catch(Exception e){
}
}
}
Please check with this code and let me know if it has worked or not.
Thanks
Prosenjit
All Answers
Tell me one thing, have you made a refference of old Opportunity into the new Opportunity ? If yes, you code is not binding them. please confirm that.
Thanks
Prosenjit
Opportunity oppNew = o.clone();
I then change field values and add objects to oppNew, and I can still access o. Is that what you're asking?
Other wise the trigger cannot be bulkified properly.
Thanks
Prosenjit.
I undertand you are referencing two opportunitie by their names. But its not much secure. Suppose, we have two closed won opportunities with same name. Then how can we distiguish their follow ups ?
Better way can be create a look up field of object opportunity it self, i.e. self look up . Name the field as Parent opportunity.
So that there will be a maintained hierarchy. For example, We have Op1 . Now it is closed. so Fop1 is created and Parent Opportinuty field of Fop1 will be Op1. Now Fop1 is also closed and again Fop2 is created as a follow up . So the hierarchy will be like Op1 -> Fop1 -> Fop2. We can redirect to all the previous opportunities from the current open opportunity by that field.
So,, when we create a New Opportunity from a closed we can easily track their Contact Roles and copy to that particular new Opportunity.
This is just a good practice suggestion. It might vary from your client specification.
By the way, Their is an standard object OpportunityContactRole which is responcible for storing contact role information.
Fields are ,
- ContactId : which is the look up to the Contact.
- OpportunityId : which the look up Opportunity (this field should be update in your trigger from closed to new).
If you are stick with you previous data model I can help with some updated code but that will violate some best practice rule , I think. Remaining is depending on you cilent specification.Thanks
Prosenjit.
I've only been coding in Apex for a few weeks, so this stuff is still all fairly new to me. Thanks for your help.
Hi Travis,
here is your code which will copy the Contact Roles. I haven't change the other codes. Just only added codes which will add contact roles.
Thanks :)
Error:Apex trigger Create_followup caused an unexpected exception, contact your administrator: Create_followup: execution of BeforeUpdate caused by: System.SObjectException: Field is not writeable: OpportunityContactRole.OpportunityId: Trigger.Create_followup: line 41, column 1
Please check with this code and let me know if it has worked or not.
Thanks
Prosenjit
Regards
Prosenjit