0
trigger ClosedOpportunityTrigger on Opportunity (before insert, before update ) {
  List<Task> OpTaskList = New List<Task> () ;

  if (Trigger.isinsert)  
  { 
    For (Opportunity op : Trigger.New)
    {     
      Task NwTask = New Task() ;

      If (op.StageName =='Closed Won')       
      {      
        NwTask.whatid = op.id ;
        NwTask.subject = 'Followup Test Task' ;
        OpTaskList.add(NwTask) ;
      }
    // insert Nwtask ;
    }
  }     

  If (Trigger.IsUpdate)
  {     
    Map<id,Opportunity> OpTaskMap = new Map<id,Opportunity>([Select id, Name, StageName ,
      (Select whatid from Tasks where whatid = Null )  
     from Opportunity where StageName = 'Closed Won']) ;

    System.debug ( 'The Size of the Task Map is ' + ' ' + OpTaskMap.size() );

    For (Opportunity op : Trigger.New)
    {
      Opportunity o = OpTaskMap.get(op.id) ;

      If (o.id != Null) 
      {
        Task NewTask = New Task () ; 
        NewTask.whatid = o.id ;
        NewTask.subject = 'Followup Test Task' ;
        OpTaskList.add(NewTask) ;
      }
    }
  }
3
  • On insert you are trying to assign opportunity ID to the task .In before insert the opportunity does not have ID yet.Go for after trigger. Refer the execution flow in Sales force. Commented Mar 18, 2016 at 1:34
  • No chinmay .. id is being used only for before update.. and the unit blocks of before insert and before update have been seperated Commented Mar 18, 2016 at 5:21
  • I am speaking about op.ID when you are creating the task in the is insert block Commented Mar 18, 2016 at 5:22

3 Answers 3

3

You should not use code to accomplish this objective. Instead use Process Builder to create a flow.

  1. Navigate to Create > Workflows & Approvals > Process Builder.

  2. Click New.
    Fill in Process Name > Create Followup Task.
    No need to fill in API Name, it will auto-populate.
    You may fill in an optional Description.
    Click Save.

  3. Click + Add Object.
    Select Opportunity.
    Click Save.

  4. Click + Add Criteria.
    Fill in Criteria Name > Insert.
    Select Formula Evaluates to True.
    Fill in OR(ISNEW(), [Opportunity].StageName ="Closed Won").
    Click Save.

  5. Click + Add Action.
    Select Action Type > Create a Record.
    Fill in Action Name > Create Task.
    Select Record Type > Task.
    Select Field > Related To ID.
    Select Type > Reference.
    Select Value > [Opportunity].Id.
    Add other fields as above.
    Click Save.

  6. Click Activate.


If you really really need to use Apex, you can make your code work. You should look at Trigger Frameworks and Apex Trigger Best Practices and An Introduction to Exception Handling, but the basic issue is that you never insert your List<Task>. Additionally, you should always perform cross-object logic in your after triggers. This will ensure that the Id is present.

trigger on Opportunity (after insert, after update)
{
    List<Task> followupTasks = new List<Task>();
    if (trigger.isAfter)
    {
        if (trigger.isInsert) { /*do stuff*/ }
        if (trigger.isUpdate) { /*do stuff*/ }
    }
    try
    {
        insert followupTasks;
    }
    catch (DmlException dmx)
    {
        for (Integer i = 0; i < dmx.getNumDml(); i++)
        {
            Id whatId = followUpTasks[dmx.getDmlIndex(i)].WhatId;
            trigger.newMap.get(whatId).addError(dmx);
        }
    }
}
1
1

As Adrian pointed out since you will need access to the opportunity id you want to use after vs before. Below is a great visual flow chart of when to use which, read the full article here.
Also be careful as you are attempting to do an insert on the NwTask variable on line 16 which is inside of a for loop and is not following bulkification best practices. Since you have a list of tasks and are adding the task to that list you will want to perform the dml operation on the entire list outside of the for loop. Inside of the IsUpdate section of your trigger you are creating the tasks but you are not inserting them but again make sure to insert the entire list outside of the for loop.
Also to note in your isupdate section of your trigger you are querying all opportunities not just items being updated. Not sure what the business logic is here but you definitely do not want to proceed with it the way it is. I would recommend starting with the after insert and get that all buttoned up and then move into the after update. sfdc99

4
  • 1
    Nice job expanding the explanation. I try to let the code speak for itself, but that certainly leads to some (many, perhaps) missing the point.
    – Adrian Larson
    Commented Mar 18, 2016 at 16:29
  • Thanks Jenny and Adrian. Normal circumstance wud use an after insert and after update trigger - but this problem is a salesforce trailhead problem asking for use of before insert and before update. The business logic in the is.update section is that want to insert a followup task to only those opportunities - which donot have a followup task already created and whose stagename = 'Closed Won'. Also will follow your advice of updating the task list after exitting the for loop Commented Mar 19, 2016 at 9:19
  • @RajivV.Subramanian I think you are misinterpreting something in that challege, it doesn't state which context to use, it's for you to decide which is best.
    – Jenny B
    Commented Mar 19, 2016 at 13:37
  • Think you are right :-) Commented Mar 19, 2016 at 18:50
-1

Here is my code : if you want to go with apex class

==================Apex Class =======================

public class OpportunityApexClass {

    public static void opportunityTrigger(list<Opportunity> varOpportunity)
    {
        list<Task> varTask = new list<Task>();
     for(Opportunity varopp : varOpportunity)
        {
         if(varopp.StageName == 'Closed Won')
            { 
                Task varTa = New Task();
                varTa.Subject ='Follow Up Test Task';
                varTa.Status ='Not Started';
                varTa.WhatId = varopp.Id;
                 varTask.add(varTa);
            } 
        }
         insert varTask; 
    }
}

===================Trigger==========================

trigger ClosedOpportunityTrigger on Opportunity (before insert,before update) {

    if(Trigger.isbefore == True && Trigger.isinsert == True)
    {
        OpportunityApexClass.opportunityTrigger(Trigger.new);   
    }
    if(Trigger.isbefore == True && Trigger.isupdate == True)
    {
        OpportunityApexClass.opportunityTrigger(Trigger.new);
    }

}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .