Preface: this post is part of the SFDC99 Challenges series.
Can you find everything wrong with this trigger?!
Fix this trigger, paste it in the comments, and I’ll let you know how you did!
// Automatically create a Renewal Opp for closed won deals trigger CreateRenewal on Opportunity (before update) { // Create a Map to store all renewal opps for bulk inserting Map<Id, Opportunity> renewals = new Map<Id, Opportunity>(); for (Opportunity opp : Trigger.new) { // Only create renewal opps for closed won deals if (opp.StageName.contains('Closed')) { Opportunity renewal = new Opportunity(); renewal.AccountId = 'opp.AccountId'; renewal.Name = opp.Name + 'Renewal'; renewal.CloseDate = opp.CloseDate + 365; // Add a year renewal.StageName = 'Open'; renewal.RecordType = 'Renewal'; renewal.OwnerId = opp.OwnerId; renewals.put(renewal.Id, renewal); } } // Bulk insert all renewals to avoid Governor Limits insert renewals; }
Lots of good errors in this one – many of the most common errors I see from new developers!
Best of luck!
//Try this one.. It is working to create a renewal opportunity… for the same opp.
trigger CreateRenewal on Opportunity (after update) //event Name not be before
{
// Create a Map to store all renewal opps for bulk inserting
Map renewals = new Map();
for (Opportunity opp : Trigger.new)
{
// Only create renewal opps for closed won deals
if (opp.StageName.contains(‘Closed Won’)) //this is not Closed
{
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId; //string value not applicable
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate + 365; // Add a year
renewal.StageName = ‘Open’;
//renewal.RecordType = ‘Renewal’; (not applicable)
renewal.Contact_Name__c= opp.Contact_Name__c;//this is mandate in my system..(optional)
renewal.OwnerId = opp.OwnerId;
renewals.put(renewal.Id, renewal);
}
}
// Bulk insert all renewals to avoid Governor Limits
insert renewals.values();
}
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (before update) {
// Create a Map to store all renewal opps for bulk inserting
Map renewals = new Map();
for (Opportunity opp : Trigger.new) {
// Only create renewal opps for closed won deals
if (opp.StageName == ‘Payment Made’) {
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = ‘New Renewal Opportunity’;
renewal.CloseDate = Date.today();
renewal.StageName = ‘In Contract’;
renewal.RecordTypeId = ‘0120N000000dfvtQAA’;
renewal.OwnerId = opp.OwnerId;
renewals.put(renewal.Id, renewal);
}
}
// Bulk insert all renewals to avoid Governor Limits
insert renewals.values();
}
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (after update) {
// Create a list to store all renewal opps for bulk inserting
List renewals = new List();
Id idRecType = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get(‘Renewal’).getRecordTypeId();
for (Opportunity opp : Trigger.new) {
// Only create renewal opps for closed won deals
if (opp.IsClosed && opp.IsWon && Trigger.oldMap.get(opp.Id).IsClosed == FALSE) {
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘ Renewal’;
renewal.CloseDate = opp.CloseDate.addDays(365); // Add a year
renewal.StageName = ‘Open’;
renewal.RecordTypeId = objRecType.Id;
renewal.OwnerId = opp.OwnerId;
renewals.add(renewal);
}
}
// Bulk insert all renewals to avoid Governor Limits
insert renewals;
}
change objRecType.Id to idRecType
trigger CreateRenewal on Opportunity (after update) {
//Map renewals = new Map();
List lstOppty = Trigger.new;
Map mapOppty = Trigger.oldMap;
List renewals = new List();
for(Opportunity opp: lstOppty){
if(opp.StageName.contains(‘Closed’) && opp.StageName != mapOppty.get(opp.Id).StageName){
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate + 365;
renewal.StageName = ‘Open’;
//renewal.RecordType.Name = ‘Renewal’;
renewal.OwnerId = opp.OwnerId;
renewals.add(renewal);
}
}
insert renewals;
}
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (after update) {
// Create a Map to store all renewal opps for bulk inserting
List renewals = new List();
for (Opportunity opp : Trigger.new) {
// Only create renewal opps for closed won deals
if (opp.StageName == ‘Closed Won’) {
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate + 365; // Add a year
renewal.StageName = ‘Open’;
renewal.RecordTypeId = opp.RecordTypeId;
renewal.OwnerId = opp.OwnerId;
renewals.add(renewal);
}
}
// Bulk insert all renewals to avoid Governor Limits
if (renewals.size() > 0 )
insert renewals;
}
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (after update) {
// Create a Map to store all renewal opps for bulk inserting
List renewals = new List();
Id recTypeId = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get(‘Renewal’).getRecordTypeId();
for (Opportunity opp : Trigger.new) {
Date opptyDate = opp.CloseDate;
Date renewOpptyDate = opptyDate.addDays(365);
// Only create renewal opps for closed won deals
if (opp.StageName == ‘Closed Won’) {
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘ Renewal’;
renewal.CloseDate = renewOpptyDate;// Add a year
renewal.StageName = ‘Open’;
renewal.RecordTypeId = recTypeId;
renewal.OwnerId = opp.OwnerId;
renewals.add(renewal);
}
}
// Bulk insert all renewals to avoid Governor Limits
insert renewals;
}
Hello,
Here’s my run at it:
Few notes:
I believe this doesn’t need to be a before update, as we are not modifying the Opportunity record at all. Also, it should not have anything to do with Insert, unless you’re inserting opportunities which are already closed won, which you shouldn’t be doing in general.
Getting the record type dynamically is important.
You can’t insert a map as written in the trigger, this needs to be a list of Opportunities to insert properly.
Making sure this fires only for when Opportunities CLOSE is important, many of the above examples will continue to fire every time a closed opportunity is updated.
You can assign values to fields in the opportunity creation line, inline, which leads to a shorter, cleaner piece of code.
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (after update) {
Id RenewalOppRecordTypeID = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get(‘Renewal’).getRecordTypeId();
List RenewalOpportunities = new List ();
for (integer i = 0; i < trigger.new.size(); i++){
if(Trigger.New[i].IsClosed == True && Trigger.Old[i].isClosed == False){
Opportunity renewalOpp = new Opportunity(AccountId = 'opp.AccountId', Name = opp.Name + 'Renewal', CloseDate = opp.CloseDate.addYear(), StageName = 'Open', RecordTypeID = RenewalOppRecordTypeID, OwnerID = opp.OwnerID);
renewalOpportunities.add(renewalOpp);
}
}
// Bulk insert all renewals to avoid Governor Limits
insert renewalOpportunities;
}
Oops.
if(Trigger.New[i].StageName == ‘Closed Won’ && Trigger.Old[i].isClosed == False)
Makes sense that renewals would only come from CW opps but I spaced it when rewriting the rest.
Also, note, comments on this site remove anything between the greater than/less than signs, so that list should be
List Renewalopportunities = new list ();
Second update. Really hates those brackets.
List (Opportunity) RenewalOpportunities = new List (Opportunity)();
Substituting for )
trigger CreateRenewal on Opportunity (before update) {
// Create a Map to store all renewal opps for bulk inserting
//Map renewals = new Map();
List renewals = new List();
for (Opportunity opp : Trigger.new) {
// Only create renewal opps for closed won deals
if (opp.StageName.contains(‘Closed’)) {
Opportunity renewal = new Opportunity();
renewal.AccountId = ‘opp.AccountId’;
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate + 365; // Add a year
renewal.StageName = ‘Open’;
renewal.RecordType = ‘Renewal’;
renewal.OwnerId = opp.OwnerId;
// renewals.put(renewal.Id, renewal);
renewals.add(renewal);
}
}
//System.debug(‘opportunity’ + renewals);
// Bulk insert all renewals to avoid Governor Limits
insert renewals;
}
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (before update) {
// Create list to store all new opportunitites
List renewals = new List();
for (Opportunity opp : Trigger.new) {
// Only create renewal opps for closed won deals
if (opp.StageName.equalsIgnoreCase(‘Closed Won’)) {
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate.addDays(365) ; // Add a year
renewal.StageName = ‘Open’;
renewal.RecordType = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get(‘Renewal’).getRecordTypeId();
renewal.OwnerId = opp.OwnerId;
renewals.add(renewal);
}
}
// Bulk insert all renewals to avoid Governor Limits
insert renewals;
}
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (before update) {
// Create a Map to store all renewal opps for bulk inserting
list renewals = new list();
for (Opportunity opp : Trigger.new) {
// Only create renewal opps for closed won deals
if (opp.StageName.contains(‘Closed Won’)) {
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate + 365; // Add a year
renewal.StageName = ‘Open’;
renewal.RecordTypeID = Label.RenewalID;
renewal.OwnerId = opp.OwnerId;
renewals.add( renewal);
}
}
// Bulk insert all renewals to avoid Governor Limits
insert renewals;
}
trigger CreateRenewal on Opportunity (after update) {
List renewals=new List();
for(Opportunity opp: Trigger.new)
{
if(opp.stageName==’Closed Won’)
{
Opportunity renewal= new Opportunity();
renewal.AccountId= opp.AccountId;
renewal.Name= opp.Name + ‘Renewal’;
renewal.CloseDate= opp.CloseDate+365;
renewal.StageName=’Open’;
renewal.RecordType__c=’Renewal’;
renewal.OwnerId= opp.OwnerId;
renewals.add(renewal);
}
insert renewals;
}
}
Tried to make as minimal changes to the original code. Let me know if this is correct and what all improvements I can make. Thanks!!!
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (after update) {
// Create a Map to store all renewal opps for bulk inserting
//Map renewals = new Map();
List renewals = new List();
Map oldOppMap = Trigger.oldMap;
for (Opportunity opp : Trigger.new) {
// Only create renewal opps for closed won deals
if ((!oldOppMap.get(opp.Id).isClosed || !oldOppMap.get(opp.Id).isWon) && opp.isClosed && opp.isWon) {
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘ Renewal’;
renewal.CloseDate = opp.CloseDate.addYears(1); // Add a year
renewal.StageName = ‘Open’;
renewal.RecordType = ‘Renewal’;
renewal.OwnerId = opp.OwnerId;
renewals.add(renewal);
}
}
// Bulk insert all renewals to avoid Governor Limits
insert renewals;
}
Made a minor change to my previously commented code. Changed “RecordType” to “RecordTypeId” to set the renewal record type.
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (after update) {
// Create a Map to store all renewal opps for bulk inserting
//Map renewals = new Map();
List renewals = new List();
Map oldOppMap = Trigger.oldMap;
for (Opportunity opp : Trigger.new) {
// Only create renewal opps for closed won deals
if ((!oldOppMap.get(opp.Id).isClosed || !oldOppMap.get(opp.Id).isWon) && opp.isClosed && opp.isWon) {
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘ Renewal’;
renewal.CloseDate = opp.CloseDate.addYears(1); // Add a year
renewal.StageName = ‘Open’;
renewal.RecordTypeId = Label.RenewalOppRecordTypeId;
renewal.OwnerId = opp.OwnerId;
renewals.add(renewal);
}
}
// Bulk insert all renewals to avoid Governor Limits
insert renewals;
}
As someone else pointed out, since the new opps have yet to be inserted, the renewal.Id will by null and since this is used as a key, the “renewals” map will only contain one record, the last one inserted with key Id==null.
Hi David,
Combining all posts of chapter 6, I have written this trigger. Please see the code and suggest for any improvements.
Trigger:-
trigger CreateRenewal on Opportunity (before update, after insert) {
//Create a renewal opportuniy for every ‘Closed Won’ opp
if (Trigger.isbefore) {
if (Trigger.isupdate) {
opp_renewal_clas ors = new opp_renewal_clas(Trigger.oldMap, Trigger.newMap);
ors.createrenewalopps();
}
}
//Send an email for every newly created opportunity
if (Trigger.isafter) {
if(Trigger.isinsert) {
opp_renewal_clas_email orse = new opp_renewal_clas_email(Trigger.new);
orse.sendanemail();
}
}
}
Apex classes (before update):-
public class opp_renewal_clas {
//Attributes
Map oldstages;
Map newstages;
//Custom setting for closed won
Renew_new__c settings = Renew_new__c.getValues(‘Allow’);
String closewon = settings.Renew_StageName__c;
//Constructor
public opp_renewal_clas(Map oldstagenames, Map newstagenames) {
oldstages = oldstagenames;
newstages = newstagenames;
}
//Create a renewal opportuniy for every ‘Closed Won’ opp
public void createrenewalopps() {
Map assignrenewals = new Map();
for (Opportunity wonopp : newstages.values()) {
if (oldstages.get(wonopp.Id).StageName != wonopp.StageName) {
if(wonopp.StageName == closewon) {
Opportunity newopps = new Opportunity();
newopps.AccountId = wonopp.AccountId;
newopps.Name = wonopp.Name + ‘ Renewal’;
newopps.CloseDate = wonopp.CloseDate + 365;
newopps.StageName = ‘Open’;
newopps.RecordTypeId = ‘0127F000000rXdr’;
newopps.OwnerId = wonopp.OwnerId;
assignrenewals.put(wonopp.Id, newopps);
}
}
}
List renewalopps = new List();
for (Opportunity wonopp : assignrenewals.values()) {
renewalopps.add(wonopp);
}
insert renewalopps;
System.debug(‘Number of renewal opportunities created ‘ + renewalopps.size());
}
}
Apex class (after insert):-
public class opp_renewal_clas_email {
//Attributes
List oppemails;
//Constructor
public opp_renewal_clas_email(List insertemails) {
oppemails = insertemails;
}
//Send an email for every newly created opportunity
public void sendanemail(){
List renewaloppmails = new List();
for (Opportunity wonopp : oppemails) {
if(wonopp.Email__c != null) {
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
List SendTo = new List();
SendTo.add(wonopp.Email__c);
mail.setToAddresses(SendTo);
mail.setReplyTo(‘revprabu@gmail.com’);
mail.setSenderDisplayName(‘Raj’);
mail.setSubject(‘Chapter 6 posts combined trigger’);
String body = ‘Please don\’t through any error’;
mail.setHtmlbody(body);
renewaloppmails.add(mail);
}
}
Messaging.sendEmail(renewaloppmails);
}
}
Test Class:-
@IsTest
public class Testing_renewal_opportunities {
public static TestMethod void Testing_renewal_opportunities() {
//Insert new records from scratch
List testingopps = new List();
for (Integer i = 0; i < 3; i++) {
Opportunity testopps = new Opportunity();
testopps.RecordTypeId = '0127F000000raWD';
testopps.Name = 'Testingopportunity' + i;
testopps.CloseDate = Date.today() + 365;
testopps.Type = 'New Customer';
testopps.Amount = 10000;
testopps.StageName = 'Prospecting';
testopps.Email__c = 'revprabu@gmail.com'; //Email Id is mandatory
testingopps.add(testopps);
}
insert testingopps;
//Update all above records with closed won stagenames
//Custom setting with closed won
Renew_new__c customsetting = new Renew_new__c();
customsetting.Name = 'Allow';
customsetting.Renew_StageName__c = 'Closed Won';
insert customsetting;
List inopps = [SELECT Id, StageName FROM Opportunity];
List updateopps = new List();
for (Opportunity renewaltestopps : inopps) {
renewaltestopps.StageName = ‘Closed Won’;
updateopps.add(renewaltestopps);
}
update updateopps;
List updateopps_withrenewals = [SELECT Id, StageName FROM Opportunity];
System.assertEquals(updateopps_withrenewals.size(), updateopps.size() + 3);
}
}
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (before insert, before update) {
// Create List for bulk insert of new renewals
List renewalOpps = new List();
//Get RecordType ID
//String recType = [SELECT Id FROM RecordType WHERE Name = ‘Renewal’].Id;
Id recType = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get(‘Renewal’).getRecordTypeId();
for (Opportunity opp : Trigger.new) {
if (opp.StageName == ‘Closed Won’) {
Boolean createRenewal = false;
if (Trigger.isInsert) {
createRenewal = true;
} else {
if(Trigger.oldMap.get(opp.Id).StageName != ‘Closed Won’) {
createRenewal = true;
}
}
if (createRenewal) {
// Only create renewal opps for closed won deals
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘ Renewal’;
renewal.CloseDate = opp.CloseDate + 365; // Add a year
renewal.StageName = ‘Open’;
renewal.RecordTypeId = recType;
renewal.OwnerId = opp.OwnerId;
renewalOpps.add(renewal);
}
}
}
}
// Bulk insert all renewals to avoid Governor Limits
insert renewalOpps;
}
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (before update) {
List listOpp = new List();
for (Opportunity opp : Trigger.new) {
// Only create renewal opps for closed won deals
if (opp.StageName.contains(‘Closed’)) {
Opportunity renewal = new Opportunity();
renewal.AccountId = ‘opp.AccountId’;
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate + 365; // Add a year
renewal.StageName = ‘Open’;
renewal.RecordType = ‘Renewal’;
renewal.OwnerId = opp.OwnerId;
listOpp.add(renewal);
}
}
// Bulk insert all renewals to avoid Governor Limits
try{
if(listOpp.size()>0)
insert listOpp;
}
catch(Exception e){
System.debug(‘DML Exception’+e);
}
}
Small correction:
List listOpp = new List();
This shouldn’t work because you are attempting to set the Account to a String with the single quotes instead of using the variable. Also this will, create a Renewal opportunity anytime a opportunity is updated, regardless if it is already in the “closed’ stage.
Hi David,
Could you please review and suggest if can be improved further?
//CreateRenewal Trigger
trigger CreateRenewal on Opportunity (before update) {
//Before Update Trigger Handler
if (Trigger.isBefore && Trigger.isUpdate) {
CreateRenewalOpportunity.beforeUpdate(Trigger.New);
}
}
// Trigger Handler Class
public with sharing class CreateRenewalOpportunity{
public static void beforeUpdate(List newList) {
Set renewals = new Set();
for (Opportunity opp : newList) {
// Only create renewal opps for closed won deals
if (opp.StageName.contains(‘Closed’)) {
renewals.add(opp.Id);
}
}
if(!renewals.isEmpty()){
// Batch Apex
Database.executeBatch(new BulkCreateRenewalOpportunity_new(renewals),200);
}
}
}
// BATCH CLASS TO PROCESS RENEWAL INSERTS
global class BulkCreateRenewalOpportunity_new implements Database.Batchable{
Set opportunitiesToRenewId = new Set();
//Constructor initialization
global BulkCreateRenewalOpportunity_new (Set opportunities) {
opportunitiesToRenewId = opportunities;
}
global Database.QueryLocator start(Database.BatchableContext BC) {
return DataBase.getQueryLocator([Select Id,AccountId,Name,CloseDate,StageName,RecordType.Name,OwnerId
FROM Opportunity where Id in :opportunitiesToRenewId]);
}
global void execute(Database.BatchableContext BC, List scopeOpportunity) {
List opportunitiesToRenew = new List();
//get renewal record type Id
Schema.DescribeSObjectResult R = Opportunity.SObjectType.getDescribe();
Id renewalRtId = r.getRecordTypeInfosByName().get(‘Renewal’).getRecordTypeId();
for (Integer i=0;i<scopeOpportunity.size();i++){
Opportunity renewal = new Opportunity();
renewal.AccountId = scopeOpportunity.get(i).AccountId;
renewal.Name = scopeOpportunity.get(i).Name + 'Renewal';
renewal.CloseDate = scopeOpportunity.get(i).CloseDate.addYears(1); // Add a year
renewal.StageName = 'Open';
renewal.RecordTypeId = renewalRtId;
renewal.OwnerId = scopeOpportunity.get(i).OwnerId;
opportunitiesToRenew.add(renewal);
}
if(!opportunitiesToRenew.isEmpty())
insert opportunitiesToRenew;
}
global void finish(Database.BatchableContext BC) { }
}
//TEST CLASS
@isTest
private class BulkCreateRenewalOpportunity_new_Test {
static testMethod void BatchProcessAccount_TestMethod (){
Test.startTest();
// Create some test Opportunities for update by the batch job.
Opportunity[] opp = new List();
for (Integer i=0;i<10;i++) {
Opportunity o = new Opportunity(
Name='sha' + i,
StageName='Prospecting',
closedate=System.today().addMonths(1));
opp.add(o);
}
insert opp;
// Update some test Opportunities for renewal create by the batch job.
Opportunity[] oppUpdate = new List();
for (Opportunity o:[SELECT Id,Name,StageName,closedate FROM Opportunity]) {
o.StageName=’Closed Won’;
oppUpdate.add(o);
}
update oppUpdate ;
// Verify Opportunity renewals items got created
Integer i = [Select COUNT() from Opportunity where RecordType.Name = ‘Renewal’];
System.assertEquals(i, 10);
Test.stopTest();
}
}
Hello, I tried it using the below code and its not working properly. When I update an Opportunity to ‘Closed Won’, I get and Invalid data error stating “Record is read-only”. Could anyone please tell me where I am going wrong in this??
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (after update, before insert) {
List listOpp = [SELECT Id,Name,AccountId,CloseDate FROM Opportunity WHERE StageName = ‘Closed Won’];
if(listOpp.size()>0) {
List newOpp = new List();
for(Opportunity oppInLoop : Trigger.new) {
for(Integer i=0;i<listOpp.size();i++) {
oppInLoop.Name = listOpp[i].Name + 'Renewal';
oppInLoop.AccountId = listOpp[i].AccountId;
oppInLoop.CloseDate = listOpp[i].CloseDate + 365; // Add a year
oppInLoop.StageName = 'Open';
}
newOpp.add(oppInLoop);
//oppInLoop.RecordType = 'Renewal';
}
insert newOpp;
}
}
hi dear
I hope below code is help full to you
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (after update, before insert) {
List newOpp = new List();
for(Opportunity oppInLoop : Trigger.new) {
if(oppInLoop.StageName ==’Closed Won’){
Opportunity renewalOpp=new Opportunity();
renewalOpp.Name =(String)oppInLoop.Name + ‘Renewal’;
renewalOpp.AccountId = oppInLoop.AccountId;
renewalOpp.CloseDate = oppInLoop.CloseDate + 365; // Add a year
renewalOpp.StageName = ‘Open’;
newOpp.add(renewalOpp);
}
}
insert newOpp;
}
After triggers are read only,before triggers can be used to update same object
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (before update) {
// Create a Map to store all renewal opps for bulk inserting
Map renewals = new Map();
for (Opportunity opp : Trigger.new) {
// Only create renewal opps for closed won deals
if (opp.StageName.contains(‘Closed’)) { //Error 1: Opportunity has Closed won & Closed Lost. So check by ‘Closed Won’
Opportunity renewal = new Opportunity();
renewal.AccountId = ‘opp.AccountId’; //Error 2– It must be a propper 15/18 digit ID and not a String
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate + 365; // Add a year
renewal.StageName = ‘Open’; //Error 3 : Opportunity StageName doesn’t have value called as ‘OPEN’
renewal.RecordType = ‘Renewal’; // Error 3 — RecordType cannot be asssigned in this way.. Need to pass ID.
renewal.OwnerId = opp.OwnerId;
renewals.put(renewal.Id, renewal);
}
}
// Bulk insert all renewals to avoid Governor Limits
insert renewals;
}
trigger CreateRenewal on Opportunity (before update) {
// Automatically create a Renewal Opp for closed won deal
ListrenewalOpptys = new List();
for (Opportunity opp: Trigger.New){
System.debug(‘cehcking condition’);
//comparing new and old values
if((opp.StageName != Trigger.oldMap.get(opp.Id).StageName)&&(opp.StageName==’Closed Won’)){
System.debug(‘condition passed’);
//insert opportunity renewal
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate + 365; // Add a year
renewal.StageName = ‘Open’;
//renewal.RecordType = ‘Renewal’;
renewal.OwnerId = opp.OwnerId;
system.debug(‘Opportunity created’);
renewalOpptys.add(renewal);
}
}
insert renewalOpptys;
}
Hi,
First thanks so much for doing this, it’s truly appreciated.
Here is my try.
trigger CreateRenewal on Opportunity (before update) {
set idSet = new set();
List oppList = new List();
for (Opportunity opp:Trigger.new) {
Opportunity oldOpp = Trigger.Oldmap.get(opp.id);
String oldStage = oldOpp.StageName;
if(opp.StageName.contains(‘Closed’) && !oldStage.contains(‘closed’)) {
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate + 365; // Add a year
renewal.StageName = ‘Open’;
renewal.OwnerId = opp.OwnerId;
oppList.add(renewal);
}
}
insert(oppList);
}
trigger CreateRenewal on Opportunity (before update) {
// Automatically create a Renewal Opp for closed won deal
ListrenewalOpptys = new List();
//old values
for (Opportunity opp: Trigger.New){
System.debug(‘cehcking condition’);
if((opp.StageName != Trigger.oldMap.get(opp.Id).StageName)&&(opp.StageName==’Closed Won’)){
System.debug(‘condition passed’);
//insert opportunity renewal
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate + 365; // Add a year
renewal.StageName = ‘Open’;
//renewal.RecordType = ‘Renewal’;
renewal.OwnerId = opp.OwnerId;
system.debug(‘Opportunity created’);
renewalOpptys.add(renewal);
}
}
insert renewalOpptys;
}
Hi David,
This code is working. I created my first trigger with the help of maps.
trigger createrenwal on Opportunity (before update) {
if(trigger.isupdate)
{
for(Opportunity op:trigger.new)
{
opportunity oldie=trigger.oldmap.get(op.id);
boolean oldoppo=oldie.stagename.equals(‘Closed Won’);
boolean newoppo=op.stagename.equals(‘Closed Won’);
if(oldoppo!=newoppo)
{
opportunity renewal=new opportunity();
renewal.closedate=system.today().addDays(30);
renewal.stagename=’open’;
renewal.Accountid=op.Accountid;
renewal.name=op.name+’renewal’;
insert renewal;
}
}
}
}
Test class for the above trigger:
@istest
public class test_createrenewal {
static testmethod void testrenewal()
{
Account sfdc=new Account(name=’David’);
insert sfdc;
opportunity renew=new opportunity(name=’opp’,stagename=’Open’,closedate=system.today());
insert renew;
Opportunity updateoppo=[select id from opportunity where id=:renew.id];
updateoppo.stagename=’closed won’;
update updateoppo;
}
}
Hi,
If someone did a bulk update of accounts to closed, I believe this would run up against your query limits. Each time you ran through the for loop, you would do your insert. Instead, you should add your opportunities to a list, and then insert the list outside the loop. See chapter 5.
Thanks,
Hi Mathew,
Thanks for your suggestions. This code will hit governor limits, I will update based on your inputs.
Regards,
trigger CreateRenewal on Opportunity (before update)
{
List renewals = new List();
for (Opportunity opp : Trigger.new)
{
// Only create renewal opps for closed won deals
if (opp.StageName == ‘Closed Won’)
{
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate + 365; // Add a year
renewal.StageName = ‘Open’;
renewal.OwnerId = opp.OwnerId;
renewals.add(renewal);
}
}
insert renewals;
}
Hello David. Firstly, I am very new to coding. I just got an opportunity and took a salesforce administrator job and got my admin certification just a couple months ago. I am trying to learn coding so that I can be more useful, and your site is AWESOME. before taking this job 5 months ago, I had never coded anything but some choose your own adventure games on my TI-83 graphing calculator back in high school.
Either way for some reason my solution seems way shorter and less complicated than the other answers posted here, so I must be doing something wrong… (although the trigger is working in my developers edition). Please if you have time can you comment on mine?
a couple notes.
1) For some reason my developer edition did not have a “Record Type” field. I had to create one.
2) In my org, the sales people sometimes sometimes don’t enter the opportunity until it is already won (i wish i could break this habit, but they don’t want me putting any validation rules around that), so I have made it an after insert as well.
trigger CreateRenewalOpp on Opportunity (after insert, after update) {
//Create a list to place the new renewal opps in//
list renewals = new list();
for(Opportunity opp: Trigger.new){
//Only create a renewal opportunity if opportunity is closed/won//
if (opp.StageName==’Closed Won’) {
Opportunity renewal = new Opportunity();
renewal.Accountid = opp.Accountid;
renewal.Name = opp.Name + ‘ Renewal’;
renewal.CloseDate = opp.CloseDate.addDays(365); // Add a year
renewal.StageName = ‘Open’;
renewal.RecordType__c = ‘Renewal’;
renewal.OwnerId = opp.OwnerId;
renewals.add(renewal);
}
}
insert renewals;
}
Make sure to check out this post!
https://www.sfdc99.com/2014/02/25/comparing-old-and-new-values-in-a-trigger/
That makes so much sense! Thanks for your reply David! I really appreciate all you are doing for us budding apex coders!
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (before update) {
// Create a Map to store all renewal opps for bulk inserting
Map renewals = new Map();
for (Opportunity opp : Trigger.new) {
// Only create renewal opps for closed won deals
if (opp.StageName.contains(‘Closed’)) {
Opportunity renewal = new Opportunity();
renewal.AccountId = ‘opp.AccountId’;
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate + 365; // Add a year
renewal.StageName = ‘Open’;
renewal.RecordTypeId = ‘01290000000XL4z’; //Change RecordType to RecordTypeID
renewal.OwnerId = opp.OwnerId;
renewals.put(renewal.Id, renewal);
}
}
// Bulk insert all renewals to avoid Governor Limits
insert renewals.values() ; // As DML Requires Sobject and Sobject List to perform operation,Use Map.values() to get alll instanced to be updated.
}
Please change from ‘Opp.AccountId’ to Opp.AccountId (Remove single Quote). Forgot to remove it in Previous comment
Thanks
Why is everyone doing an insert in a trigger? Trigger is on opportunity and isBefore update. Any insert will throw an exception
Linus, read the first line of the trigger and you’ll see why
trigger RenewalRecordType on Opportunity (after update) {
for(Opportunity opp : Trigger.new){
if(opp.Stagename == ‘Closed Won’){
Opportunity o1 = new Opportunity();
system.debug(‘———Opp ID –‘+o1.ID);
system.debug(‘———Opp ID –‘+opp.ID);
o1.Name = opp.name + ‘Renewal’;
o1.Stagename = ‘Closed Won’;
o1.CloseDate = opp.CloseDate + 365;
o1.RecordTypeId = ‘01290000001GVdi’; // this is my record type ID
o1.tryme__Renewal_Opportunity__c = true ;
system.debug(‘——Before insert—Opp ID –‘+o1.ID);
insert o1;
system.debug(‘——After insert—Opp ID –‘+o1.ID);
}
}
}
Problems
1) Assuming it’s 365 days, Close Date should use addYears(1) since you can’t just add 365 to the date.
2) Have to use RecordTypeId instead of RecordType since Record Type is an SObject.
3) Opportunities consist of Opportunities and Opportunity Line Items.
The renewal only consists of the Opportunities in the example. Even though
the requirement doesn’t say so, I’d think that the renewal should list the
products to renew as well, their quantity, and the unit price for each.
4) Uses the wrong stage, “Closed”, instead of “Closed Won” and it doesn’t see
if the opportunity was updated to closed won.
5) When appending “Renewal” to the name, it should have a space between for
readability. If my Opp name is “My Opp” and it’s closed won, the
renewal name will be “My OppRenewal”.
6) Even though the trigger is currently using “Before Update”, it should check
for that condition to ensure the code is only running for that in case
additional trigger events are added later.
7) Using the renewal.Id makes no sense because the Id is null since it hasn’t
been inserted yet. A simple list of Opportunities to insert would suffice.
8) The StageName should be something else such as “Proposal/Price Quote”.
9) One can’t insert a map. It has to be a list.
10) Before invoking “insert” or any dml operation, see if there’s anything to do first.
Technically, the insert will still pass with an empty list but it takes more time
than is actually needed.
11) The AccountId can’t be assigned a String of ‘opp.AccountId’.
12) NitPicky…. I’d name the trigger “CreateRenewalOpportunity or make it
a more generic trigger that delegates to a “Trigger Handler”.
13) There’s no test code. Each trigger has to have at least 1% code coverage.
Solution
/*
Disclaimer: This code is uncompiled and untested.
The following assumes that
1) Multi-Currency isn’t enabled
2) Only English needs to be supported.
3) Opportunity Line Items should be renewed also
4) Only one opportunity trigger is used instead of creating one for each
“Opportunity Feature”.
5) Test Code will be created later….
*/
trigger OpportunityTrigger on Opportunity (before update){
if (Trigger.IsBefore && Trigger.IsUpdate){
OpportunityTriggerHandler.createRenewalOpportunities(Trigger.oldMap, Trigger.newMap);
}
}
public class OpportunityTriggerHandler {
private static Id RenewalOppRecordTypeIdPriv = null;
private static Id RenewalOppRecordTypeId {
get {
if (RenewalOppRecordTypeIdPriv == null){
Schema.DescribeSObjectResult R = opportunity.SObjectType.getDescribe();
RenewalOppRecordTypeIdPriv = r.getRecordTypeInfosByName().get(‘Renewal’).getRecordTypeId();
}
return RenewalOppRecordTypeIdPriv;
}
}
public static void createRenewalOpportunities(Map oldOpps, Map newOpps){
Map renewalOpps = new Map();
for (Opportunity newOpp : Trigger.New){
Opportunity oldopp = Trigger.oldMap.get(newOpp.Id);
if (isNowClosedWon(oldOpp, newOpp){
Opportunity renewalOpp = createRenewalOpp(newOpp);
renewalOpps.put(newOpp.Id, renewalOpp);
}
}
// insert only if there are items to insert.
if (renewalOpps.size() > 0){
insert renewalOpps.values();
}
else {
// No opps became closed won so return immediately. Don’t unnecessarily
// do more work than is necessary.
return;
}
List closedWonOppLines = getClosedWonOppLines(renewalOpps.keySet());
List renewalOppLines = new List();
for (OpportunityLineItem closedWonOppLine : closedWonOppLines){
// Deep clone without preserving the id, timestamps, or autonumber
OpportunityLineItem renewalOppLine = closedWonOppLine.clone(false, true, false, false);
// Link the renewal opportunity line item to the appropriate renewal opportunity
Id renewalOppId = renewalOpps.get(closedWonOppLine.OpportunityId).Id;
renewalOppLine.OpportunityId = renewalOppId;
renewalOppLines.add(renwalOppLine);
}
if (renewalOppLines.size() > 0){
insert renewalOppLines;
}
}
private static Boolean isNowClosedWon(Opportunity oldOpp, Opportunity newOpp){
return oldOpp.StageName != newOpp.StageName &&
newOpp.StageName == ‘Closed Won’;
}
private static Opportunity createRenewalOpp(Opportunity closedWonOpp){
Opportunity renewalOpp = new Opportunity();
renewalOpp.AccountId = closedWonOpp.AccountId;
renewalOpp.Name = closedWonOpp.Name + ‘ Renewal’;
renewalOpp.CloseDate = closedWonOpp.CloseDate.addYears(1);
renewalOpp.StageName = ‘Proposal/Price Quote’;
renewalOpp.RecordTypeId = RenewalOppRecordTypeId;
renewalOpp.OwnerId = opp.OwnerId;
return renewalOpp;
}
private List getClosedWonOppLines(Set closedWonOppIds){
return [Select Id,
Name,
OpportunityId,
PricebookEntryId,
Product2Id,
Quantity,
UnitPrice,
TotalPrice
from OpportunityLineItem
where OpportunityId = :closedWonOppIds];
}
}
I added some extra nice to haves, didn’t actually test it so there’s probably an error or typos lurking.
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (before update) {
// Create a list to store all renewal opps for bulk inserting
list renewals = new list();
//get renewal record type Id
Schema.DescribeSObjectResult R = opportunity.SObjectType.getDescribe();
id renewalRtId = r.getRecordTypeInfosByName().get(‘Renewal’).getRecordTypeId();
//build a map of opportunityStage for isWon && isactive
map stageMap = new map();
for(opportunityStage o:[SELECT masterLabel, isWon FROM opportunityStage WHERE isActive = true AND isWon = true]){
stageMap.put(o.masterLabel,o.isWon);
}
for (Opportunity opp : Trigger.new) {
// Only create renewal opps for closed won deals
if (stageMap.get(opp.StageName) != null && opp.oldMap.get(‘stageName’) != opp.stageName && opp.renewal_opportunity__c == null) {
renewals.add( new Opportunity(
AccountId = opp.AccountId,
Name = opp.Name + ‘ Renewal’,
CloseDate = opp.closedDate.addYears(1),
StageName = ‘Open’,
RecordTypeId = renewalRtId,
OwnerId = opp.OwnerId,
external_id__c = opp.id
));
}
}
//insert the renewal opps
try{
Database.SaveResult[] srList = Database.insert(renewals, false);
set renewalIds = new set();
//put the new opp ids into a set
for (Database.SaveResult sr : srList) {
if (sr.isSuccess()) {
renewalIds.add(sr.getId());
}
}
map renewalMap = new map();
//put the renewal opp external_id__c(id of opportunity that created it) and id into a map
for(opportunity renew:[SELECT id, external_id__c FROM opportunity WHERE id in: renewalIds]){
renewalMap.put(renew.external_id__c,renew.id);
}
//fill in the renewal_opportunity__c field on the closed/won opportunity to link them to their renewal
for(opportunity o:trigger.new){
if(renewalMap.get(o.id) != null){
o.renewal_opportunity__c = renewalMap.get(o.id);
}
}
}catch(excecption e){
system.debug(‘# # # exception: ‘+e);
}
}
trigger CreateRenewal on Opportunity (after update) {
list renewals = new list();
id recTypeId = Schema.Sobjecttype.Opportunity.getRecordTypeInfosByName().get(‘Renewal’).getRecordTypeId();
for (Opportunity opp : Trigger.new)
{
if (opp.isWon)
{
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate.addDays(365);
renewal.StageName = ‘Qualification’;
renewal.RecordTypeId = recTypeId;
renewals.add(renewal);
}
}
insert renewals;
}
Changes :
1. Before update to after update
2. map to list
3. Changed if condition from if (opp.StageName.contains(‘Closed’)) to if (opp.isWon)
4. Created new variable(recTypeId) of type id to save the id of record type Renewal.
5. Changed the value for record type from enewal.RecordType = ‘Renewal’ to renewal.RecordTypeId = recTypeId;
6. Changed date value from renewal.CloseDate = opp.CloseDate + 365 to renewal.CloseDate = opp.CloseDate.addDays(365);
7. Changed renewals.put(renewal.Id, renewal) to renewals.add(renewal);
8. removed the single quote for renewal.AccountId = ‘opp.AccountId’; to renewal.AccountId = opp.AccountId;
Hello David,
I’m inspired by your trigger puzzles and would like to give a try on this. :)
I find the below bugs in this trigger.
* opp.AccountId should not be in single quotes. Since this is a lookup to Account, it should hold only the Account Id & not a string value
* Only RecordTypeId can be used
* renewal.Id will not be available for a before insert trigger (Probably null pointer exception)
* Trigger.isBefore and Trigger.isUpdate could be used
trigger CreateRenewal on Opportunity (after update) {
list renewals = new list();//list is my preference but a map would work
for (Opportunity opp : Trigger.new) {
//only create renewal opp for deals that have just recently been closed won.
//Otherwise everytime the record was editied a renewal opportunity would be generated.
Opportunity priorvalue = Trigger.oldMap.get(opp.Id); //grab the priorvalue oppty id.
boolean alreadyClosed = priorvalue.StageName.equals(‘Closed Won’);//create flag to catch opportunities that had already been closed won.
if (opp.StageName ==’Closed Won’ && !alreadyClosed)
{
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.name + ‘ Renewal’;
renewal.CloseDate = opp.CloseDate + 365;
renewal.StageName = ‘Open’;
renewal.RecordTypeID = ‘012U000000012Q0’; //change to recordtypeID
renewal.OwnerId = opp.OwnerId;
renewals.add(renewal); //add new opp(s) to list
}
}
insert renewals;
}
Following are Issue that I see is with the below statement
1) insert renewals;
If it is “before Update” trigger on Opportunity. And the code inserts a Renewal opportunity (new)
2) renewals.put(renewal.Id, renewal);
How can you have renewal Id when it is Before Insert trigger???
So Ideal will be to do part of processing in Before Update & After Update. Also check isBefore & isAfter
In the earlier trigger its written “renewals.put(renewal.Id, renewal);”
is taken inside the for loop it shud be outside the for loop where map is declared .
Ideal steps which should be followed are:
step1.Create set of records to stagename=closed won.
step 2 Create a map with id store the opportunity.
step 3 loop through trigger.new and add business logic
trigger CreateRenewal on Opportunity (before update,before insert)
{
//create a set of records
set oSet = new set();
if( trigger.isInsert|| trigger.isUpdate)
{
for(opportunity o : trigger.new)
{
if (o.StageName ==’Closed Won’)
{
oSet.add(o.AccountId);
}
}
}
// Create a Map to store all renewal opps for bulk inserting
list oppid = [SELECT AccountId,CloseDate ,Name , StageName,OwnerId FROM opportunity
WHERE AccountId IN : oSet];
Map renewals = new Map ();
// Only create renewal opps for closed won deals
{ for(opportunity u : oppid)
{
renewals.put(u.Id,u);
}
}
//trigger.new and logic
list addhere = new list();
for(opportunity o : trigger.new)
{
if(o.StageName == ‘Closed Won’)
{
opportunity oppis = renewals.get(o.Id);
if (oppis != null)
{
o.AccountId = oppis.AccountId;
o.Name = oppis.Name + ‘Renewal’;
o.CloseDate = oppis.CloseDate + 365; // Add a year
o.StageName = ‘Open’;
o.OwnerId = oppis.OwnerId;
}
}
}
// Bulk insert all renewals to avoid Governor Limits
insert addhere;
}
This sounds fun. Went for a simple working solution. About to find out if markdown is supported.
“`
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity (after insert, after update) {
// Create a List to store all renewal opps for bulk inserting
List renewals = new List();
Id renewalRT = [SELECT Id FROM RecordType WHERE Name = ‘Renewal’].Id;
for (Opportunity opp : Trigger.new) {
// Only create renewal opps for closed won deals
if (opp.isWon && opp.isClosed) {
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘ Renewal’;
renewal.CloseDate = opp.CloseDate + 365; // Add a year
renewal.StageName = ‘Open’;
renewal.RecordTypeId = renewalRT;
renewal.OwnerId = opp.OwnerId;
renewals.add(renewal);
}
}
// Bulk insert all renewals to avoid Governor Limits
insert renewals;
}
“`
trigger CreateRenewal on Opportunity (after update, after insert) {
List renewals = new List();
for (Opportunity opp : Trigger.new) {
// Only create renewal opps for closed won deals
if (opp.StageName.contains(‘Closed’)) {
Opportunity renewal = new Opportunity();
renewal.Account = opp.Account;
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate + 365; // Add a year
renewal.StageName = ‘Open’;
renewal.RecordType = ‘Renewal’;
renewal.Owner = opp.Owner;
renewals.add(renewal);
}
}
insert renewals;
}
How does this look?
trigger CreateRenewal on Opportunity (before update,before insert)
{
****//create a set of records
set oSet = new set();
if( trigger.isInsert|| trigger.isUpdate)
{
for(opportunity o : trigger.new)
{
if (o.StageName == ‘Closed’)
{
oSet.add(c.AccountId);
}
}
}
****// Create a Map to store all renewal opps for bulk inserting
list oppid = [SELECT AccountId,CloseDate ,Name , StageName,OwnerId FROM opportunity
WHERE AccountId IN : oSet];
Map renewals = new Map();
// Only create renewal opps for closed won deals
{ for(opportunity u : oppid)
{
renewals.add(u.AccountId,u);
}
}
****//trigger.new and logic
list addhere = new list();
for(opportunity o : trigger.new)
{
if(o.StageName==’Closed’)
{
opportunity oppis = renewals.get(o.AccountId);
if (oppis != null)
{
o.AccountId = oppis.AccountId;
o.Name = oppis.Name + ‘Renewal’;
o.CloseDate = oppis.CloseDate + 365; // Add a year
o.StageName = ‘Open’;
o.RecordType = ‘Renewal’;
o.OwnerId = oppis.OwnerId;
}
}
}
// Bulk insert all renewals to avoid Governor Limits
insert addhere;
}
in reference to previous code:
trigger event ahould be : after insert,after update
and not before insert,before update
Hi David,
This is my code. The challenge was pretty good, though I am sure there is a better way to add one year to the CloseDate, as this one would be wrong in a leap year.
trigger CreateRenewal on Opportunity (before update) {
List renewals = new List();
for (Opportunity opp : Trigger.new) {
if (opp.StageName.contains(‘Closed’)) {
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘ Renewal’;
renewal.CloseDate = opp.CloseDate + 365;
renewal.StageName = ‘Open’;
renewal.RecordType = [select id from recordtype where SobjectType=’Opportunity’ and Name = ‘Renewal’].get(0);
renewal.OwnerId = opp.OwnerId;
renewals.add(renewal);
}
}
insert renewals;
}
Hi David.
Here is my code :
trigger CreateRenewal on Opportunity (after insert, after update) {
List renewals = new List();
List closedOpp = Trigger.new;
RecordType openRecordType = [SELECT Id FROM RecordType WHERE Name LIKE ‘%Renewal%’];
for(Opportunity opp: closedOpp){
if(opp.IsClosed){
Opportunity newOpp = new Opportunity();
newOpp.AccountId = opp.AccountId;
newOpp.Name = opp.Name+’Renewal’;
newOpp.StageName = ‘Open’;
newOpp.CloseDate = opp.CloseDate + 365;
newOpp.RecordTypeId = openRecordType.Id;
newOpp.OwnerId = opp.OwnerId;
renewals.add(newOpp);
}
}
insert renewals;
}
I think It’s not perfect but worked.
woot! All Opportunity typecast for List has disappeared.
And more appropriate to change `RecordType openRecordType` into `RecordType renewalRecordType`
trigger CreateRenewal on Opportunity (before update) {
List lstRenewals = new List();
for (Opportunity opp : Trigger.new) {
// Only create renewal opps for closed won deals
if (opp.StageName.contains(‘Closed’)) {
Opportunity renewal = new Opportunity();
renewal.AccountId = opp.AccountId;
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate + 365; // Add a year
renewal.StageName = ‘Open’;
renewal.Type = ‘Renewal’;
renewal.OwnerId = opp.OwnerId;
lstRenewals.add(renewal);
}
}
insert lstRenewals;
}
oops I am not sure why it didn’t paste correctly !
* List opplist = new List ();
Map sObjectMap = Schema.getGlobalDescribe() ;
Map recordTypeInfo = resSchema.getRecordTypeInfosByName();
not able to post the correct syntax :( Cant find the delete option either !
I am relatively new to coding , but I would still like to give this a try ! Thanks David for being a huge inspiration to me :)
trigger CreateRenewal on Opportunity (before update) {
List opplist = new List();
Map sObjectMap = Schema.getGlobalDescribe() ;
Schema.SObjectType s = sObjectMap.get(‘Opportunity’) ;
Schema.DescribeSObjectResult resSchema = s.getDescribe() ;
Map recordTypeInfo = resSchema.getRecordTypeInfosByName();
Id rtId = recordTypeInfo.get(‘Renewal’).getRecordTypeId();
for (Opportunity opp : Trigger.new)
{
if (opp.Stagename.contains(‘Closed’))
{
Opportunity renewals = new Opportunity();
renewals.AccountId = opp.AccountId;
renewals.Name = opp.Name+’Renewal’;
renewals.CloseDate = opp.CloseDate + 365;
renewals.StageName = ‘Open’;
renewals.recordtypeid = rtId;
renewals.OwnerId = opp.OwnerId;
opplist.add(renewals);
}
}
insert opplist;
}
Does this work? I basically used my Developer edition and used a Trigger object to edit it.
// Automatically create a Renewal Opp for closed won deals
trigger CreateRenewal on Opportunity_c (before update) {
// Create a Map to store all renewal opps for bulk inserting
Map renewals = new Map();
for (Opportunity opp : Trigger.new) {
// Only create renewal opps for closed won deals
if (opp.StageName.contains(‘Closed’)) {
Opportunity renewal = new Opportunity();
renewal.AccountId = ‘opp.AccountId’;
renewal.Name = opp.Name + ‘Renewal’;
renewal.CloseDate = opp.CloseDate + 365; // Add a year
renewal.StageName = ‘Open’;
renewal.Type = ‘Renewal’;
renewal.OwnerId = opp.OwnerId;
renewals.put(renewal.Id, renewal);
}
}
// Bulk insert all renewals to avoid Governor Limits
// insert renewals
}