Salesforce coding lessons for the 99%
Finally, Apex tutorials for point-and-click admins! Written by a self-taught Google engineer.
  • Beginner Tutorials
    • Apex
    • Certifications
    • Career Info
    • Technical Architect
    • Visualforce
    • Videos
  • Apex Academy
  • Success Stories
  • About Me
  • Misc
    • Mailbag
    • Challenges
    • Links
    • Login to my Org
Follow @dvdkliuor SUBSCRIBE!

Fix this trigger: Opportunity Renewal

September 27, 2014

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!

62 Comments
gunjan
June 9, 2022 @ 11:00 pm

//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();
}

Reply
Megatron
September 30, 2021 @ 8:25 am

// 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();

}

Reply
Alex
January 16, 2021 @ 9:06 pm

// 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;
}

Reply
    Alex
    January 16, 2021 @ 9:07 pm

    change objRecType.Id to idRecType

    Reply
Suan Khuptong
April 14, 2020 @ 1:46 pm

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;
}

Reply
K G
January 23, 2020 @ 10:05 am

// 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;
}

Reply
madhulika ramabhotla
August 3, 2019 @ 3:49 pm

// 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;
}

Reply
Dylan Pfandler
April 27, 2019 @ 4:53 pm

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;
}

Reply
    Dylan Pfandler
    April 27, 2019 @ 5:07 pm

    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 ();

    Reply
      Dylan Pfandler
      April 27, 2019 @ 5:08 pm

      Second update. Really hates those brackets.
      List (Opportunity) RenewalOpportunities = new List (Opportunity)();
      Substituting for )

      Reply
Test
March 26, 2019 @ 2:00 pm

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;
}

Reply
Ameya
September 3, 2018 @ 2:28 am

// 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;
}

Reply
Utkarsh
February 1, 2018 @ 11:04 pm

// 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;
}

Reply
Kundan Kumar
January 31, 2018 @ 4:36 am

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;

}
}

Reply
Satyajeet Maharana
September 7, 2017 @ 3:57 am

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;
}

Reply
    Satyajeet Maharana
    September 7, 2017 @ 4:00 am

    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;
    }

    Reply
Chris Wolf
August 10, 2017 @ 5:43 pm

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.

Reply
Prabhu
July 18, 2017 @ 2:33 pm

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);
}
}

Reply
Darrell Gallegos
June 22, 2017 @ 11:07 am

// 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;

}

Reply
naveenkumarbh
December 26, 2015 @ 3:02 am

// 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);
}
}

Reply
    naveenkumarbh
    December 26, 2015 @ 3:04 am

    Small correction:
    List listOpp = new List();

    Reply
    Anonymous
    June 22, 2017 @ 7:19 am

    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.

    Reply
Bharat
September 28, 2015 @ 5:12 pm

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();
}
}

Reply
Sid
September 27, 2015 @ 9:26 pm

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;
}
}

Reply
    Masthan
    March 1, 2016 @ 4:35 am

    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;
    }

    Reply
    Sony
    June 29, 2018 @ 11:05 am

    After triggers are read only,before triggers can be used to update same object

    Reply
Ayan Sarkar
September 4, 2015 @ 6:14 am

// 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;
}

Reply
neevenn
June 10, 2015 @ 10:40 am

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;
}

Reply
Mathew
February 26, 2015 @ 12:02 pm

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);

}

Reply
    Anonymous
    June 10, 2015 @ 8:36 am

    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;
    }

    Reply
Lokesh
February 2, 2015 @ 4:56 am

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;
}
}
}
}

Reply
    Lokesh
    February 2, 2015 @ 5:41 am

    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;

    }
    }

    Reply
    Mathew
    February 26, 2015 @ 12:06 pm

    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,

    Reply
      Lokesh
      March 9, 2015 @ 3:04 am

      Hi Mathew,

      Thanks for your suggestions. This code will hit governor limits, I will update based on your inputs.

      Regards,

      Reply
Snehal
January 21, 2015 @ 1:09 am

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;
}

Reply
Kartez T.
November 20, 2014 @ 10:26 am

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;
}

Reply
    David Liu
    November 20, 2014 @ 8:20 pm

    Make sure to check out this post!
    https://www.sfdc99.com/2014/02/25/comparing-old-and-new-values-in-a-trigger/

    Reply
      Kartez T.
      November 21, 2014 @ 7:29 am

      That makes so much sense! Thanks for your reply David! I really appreciate all you are doing for us budding apex coders!

      Reply
    Shadab Hussain
    February 19, 2015 @ 11:41 pm

    // 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.
    }

    Reply
      Shadab Hussain
      February 19, 2015 @ 11:49 pm

      Please change from ‘Opp.AccountId’ to Opp.AccountId (Remove single Quote). Forgot to remove it in Previous comment

      Thanks

      Reply
Linus Ilaum
November 1, 2014 @ 10:26 am

Why is everyone doing an insert in a trigger? Trigger is on opportunity and isBefore update. Any insert will throw an exception

Reply
    Luke freeland
    November 2, 2014 @ 5:22 am

    Linus, read the first line of the trigger and you’ll see why

    Reply
Swapnil
October 17, 2014 @ 10:41 pm

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);
}

}

}

Reply
Luke Freeland
October 11, 2014 @ 9:02 am

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];
}
}

Reply
Blake Tanon
October 9, 2014 @ 9:45 am

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);
}

}

Reply
Saravanan Haldurai
October 8, 2014 @ 5:48 am

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;

Reply
Poorna Prabhu
October 1, 2014 @ 5:54 am

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

Reply
Tyler Harris
September 30, 2014 @ 2:40 pm

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;

}

Reply
Tanvir Ansari
September 30, 2014 @ 7:45 am

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

Reply
chitral
September 30, 2014 @ 12:23 am

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;
}

Reply
Matt Mitchener
September 29, 2014 @ 8:56 am

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;
}
“`

Reply
Harrison
September 29, 2014 @ 7:23 am

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?

Reply
chitral
September 29, 2014 @ 4:21 am

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;
}

Reply
    chitral
    September 29, 2014 @ 5:28 am

    in reference to previous code:
    trigger event ahould be : after insert,after update
    and not before insert,before update

    Reply
Zoom Zoom
September 29, 2014 @ 3:55 am

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;
}

Reply
Alfian
September 28, 2014 @ 11:51 pm

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.

Reply
    Alfian
    September 29, 2014 @ 12:00 am

    woot! All Opportunity typecast for List has disappeared.
    And more appropriate to change `RecordType openRecordType` into `RecordType renewalRecordType`

    Reply
Giri
September 28, 2014 @ 11:13 pm

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;
}

Reply
Olive
September 27, 2014 @ 10:17 pm

oops I am not sure why it didn’t paste correctly !
* List opplist = new List ();
Map sObjectMap = Schema.getGlobalDescribe() ;
Map recordTypeInfo = resSchema.getRecordTypeInfosByName();

Reply
    Olive
    September 27, 2014 @ 10:19 pm

    not able to post the correct syntax :( Cant find the delete option either !

    Reply
Olive
September 27, 2014 @ 10:12 pm

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;

}

Reply
Miguel G
September 27, 2014 @ 4:02 pm

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
}

Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *


*

*

Theme: Simple Style by Fimply