+ Start a Discussion
José Teixeira GomesJosé Teixeira Gomes 

Apex Trigger with field dependencies

Hello, I am new to Salesforce, currently still with a trial version, and I am trying to create an Apex Trigger but before I get into it I wanted to ask if my idea is even possible. So I want a trigger that fires when a task is completed and creates a task the same account in (+) a specific time period. For the trigger part I want it to: (1) change the due date to the date it is completed; (2) schedule the next task depending on an account custom field (frequency); (3) assign it to a contact of that account, but only the one that is assigned as primary (custom field). Also the trigger needs to be built so it can handle mass updates of accounts/contacts/tasks.

I have tried to build something but still have very limited knowledge. If anyone has built anything similar and would like to share it with I would be extremely appreciated. Any help is welcome! Thanks
Best Answer chosen by José Teixeira Gomes
José Teixeira GomesJosé Teixeira Gomes
The final code for the follow up tasks, helped in another discussion:

Trigger FollowUpTask on Task(after update) {

     Set<Id> completedTasks = new Set<Id>();
     Set<Id> contactIds = new Set<Id>();
     Set<Id> accountIds = new Set<Id>();
 
     for (Task task: Trigger.new) {
     
          if (task.Status != Trigger.oldMap.get (task.Id).Status && task.Status=='Completed')
               completedTasks.add(task.Id);
               contactIds.add(task.WhoId);
               accountIds.add(task.WhatId);
          }
 
     contactIds.remove(null);
     accountIds.remove(null);
 
     Map<Id, Contact> contactMap = new Map<Id, Contact>();
     Map<Id, Account> accountMap = new Map<Id, Account>();
 
     if (!contactIds.isEmpty()) {
          contactMap = new Map<Id, Contact>([
               select Contact_Frequency__c,
                    Name
               from Contact
               where Id in :contactIds
          ]);
     }
 
     if (!accountIds.isEmpty()) {
          accountMap = new Map<Id, Account>([
               select Primary_Contact__c,
                    Name,
                    Tier__c
               from Account
               where Id in :accountIds
          ]);
     }

     List<Task> newTasks = new List<Task>();
     for (Id id: completedTasks) {
          Task task = Trigger.newMap.get(id);
          Contact contact = contactMap.get(task.WhoId);
          Account account = accountMap.get(task.WhatId);
 
          if (account == null || contact == null) {
               continue;
          }
 
          Task newTask = new Task(
               Subject = 'Follow Up ' + account.Name + '/' + contact.Name,
               OwnerId = task.OwnerId,
               WhoId = account.Primary_Contact__c,
               WhatId = account.Id,
               Priority = (account.Tier__c == 'Tier 1') ? 'High' : 'Normal'
               );    
 
          Date duedate = system.today().addDays((Integer)(contact.Contact_Frequency__c));
          newTask.ActivityDate = dueDate;
 
          newTasks.add(newTask);
     }
 
     if (!newTasks.isEmpty()) {
          insert newTasks;
     }
}


All Answers

Andy BoettcherAndy Boettcher
Hello José!

You can absolutely do that with an APEX trigger.  The first thing you should do is get famiiar with APEX triggers and how they work - I put a blog post out there that can help you out.

http://techman97.wordpress.com/2012/07/18/how-to-write-a-basic-apex-trigger/

As for the trigger itself, you would do something along these lines:
List<Task> lstInsertTasks = new List<Task>();

for(Task tsk : trigger.new) {
    if(tsk.Status == 'Completed') {
        Task tskNew = new Task();
        tskNew.WhatId = tsk.WhatId;
        (other fields here)
        lstInsertTasks.add(tskNew);
    }
}

if(lstInsertTasks.size() > 0) { insert lstInsertTasks; }
(This code is just in a post - it's not compiled or checked for errors...it's just to guide you)
José Teixeira GomesJosé Teixeira Gomes
Thanks Andy,
 
I have been trying to write something but had no success. I think that maybe it is best if I write two separate triggers: one to update the due date to the completion date if the due date is later than the completion date; and another to create the new task. I think I managed the first one:

trigger CompletedTasks on Task (after update) {


List <Task> CompletedTasks = new List <Task>();

Set <Id> TaskIds = new Set <Id> ();

if (Trigger.isUpdate) {

for(Task tsk : trigger.new)
   
    {
    if(tsk.Status != Trigger.oldMap.get (tsk.Id).Status && tsk.Status=='Completed')
        {   
            TaskIds.add (tsk.Id);
        }
    }
   
    if (!TaskIds.isEmpty () )
    {
        for (Task tsk: [select Id, Status from Task where Id in :TaskIds])
        {
            tsk.ActivityDate = System.today();
            CompletedTasks.add (tsk);
        }
   
    update CompletedTasks;

    }
  }
}

But now I am wondering if, when I write the other one, it will conflict with the first one since I still it to only fire when the task is completed (is there any order by which they trigger, or is it at the same time). Also, is it better if I include everything in the same trigger?
José Teixeira GomesJosé Teixeira Gomes
Another question. I want to create a task in x days, where x is defined in a field of a contact of the parent account of the task. Is it possible to create the task in today()+the number of that field, and how would I be able to reference that field. I would have to somehow look up the parent account of the task, lookup what contact of that account is defined as primary (custom field) and get the frequency of that contact (custom field). How can I do this?
José Teixeira GomesJosé Teixeira Gomes
The final code for the follow up tasks, helped in another discussion:

Trigger FollowUpTask on Task(after update) {

     Set<Id> completedTasks = new Set<Id>();
     Set<Id> contactIds = new Set<Id>();
     Set<Id> accountIds = new Set<Id>();
 
     for (Task task: Trigger.new) {
     
          if (task.Status != Trigger.oldMap.get (task.Id).Status && task.Status=='Completed')
               completedTasks.add(task.Id);
               contactIds.add(task.WhoId);
               accountIds.add(task.WhatId);
          }
 
     contactIds.remove(null);
     accountIds.remove(null);
 
     Map<Id, Contact> contactMap = new Map<Id, Contact>();
     Map<Id, Account> accountMap = new Map<Id, Account>();
 
     if (!contactIds.isEmpty()) {
          contactMap = new Map<Id, Contact>([
               select Contact_Frequency__c,
                    Name
               from Contact
               where Id in :contactIds
          ]);
     }
 
     if (!accountIds.isEmpty()) {
          accountMap = new Map<Id, Account>([
               select Primary_Contact__c,
                    Name,
                    Tier__c
               from Account
               where Id in :accountIds
          ]);
     }

     List<Task> newTasks = new List<Task>();
     for (Id id: completedTasks) {
          Task task = Trigger.newMap.get(id);
          Contact contact = contactMap.get(task.WhoId);
          Account account = accountMap.get(task.WhatId);
 
          if (account == null || contact == null) {
               continue;
          }
 
          Task newTask = new Task(
               Subject = 'Follow Up ' + account.Name + '/' + contact.Name,
               OwnerId = task.OwnerId,
               WhoId = account.Primary_Contact__c,
               WhatId = account.Id,
               Priority = (account.Tier__c == 'Tier 1') ? 'High' : 'Normal'
               );    
 
          Date duedate = system.today().addDays((Integer)(contact.Contact_Frequency__c));
          newTask.ActivityDate = dueDate;
 
          newTasks.add(newTask);
     }
 
     if (!newTasks.isEmpty()) {
          insert newTasks;
     }
}


This was selected as the best answer