function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Sean BarczynskiSean Barczynski 

Last Meeting Date

Hello,

I'm attempting to write my first trigger, so please bare with me while I explain.

The purpose of the trigger is to update some date fields based upon Events to show when the last meeting of various types was completed.  I've seen a few different threads on this site that I was able to pull some ideas from, but have been unable to figure out how to get one particular piece to work.  The issue comes when a meeting is Canceled or Rescheduled.  We want to keep these events in the system so we can refer back to them in the future (e.g. if a client says we haven't seen them in over a year, we can go back and see that they canceled on us twice), but we don't want these events to be reflected in the Last Meeting fields.

I believe I have it written correctly so far to update the field when a meeting is not Canceled or Rescheduled, I just don't know how to get it to work once the meeting is Canceled.  Theoretically, the field would already be updated with this meeting date, so I'd want the trigger to look back and pull the last meeting that was not canceled or rescheduled.  I have two ideas:
  • Loop through the Account's Events and find the most recent one that was not canceled or rescheduled.  I'm thinking this would cause too many database queries and may throw an error.
  • Create a second field (not visible on the Page Layout) that contains the last successful meeting date before this one.
Here's my code.  Be gentle, it's my first attempt!
 
trigger LastEventDate on Event (after insert, after update) 
{

	// The sets used to store the IDs of the Accounts or Contacts/Leads within an event that need to get updated
	Set <Id> whoIdSet = new Set <Id> ();
	Set <Id> whatIdSet = new Set <Id> ();

	for(Event e : trigger.net)
	{
		if(e.WhoId != null)
		{
			whoIdSet.add(e.WhoId);
		}
		
		if(e.WhatId != null && e.WhoId == null)
		{
			whatIdSet.add(e.WhatId);
		}
	}

	// Creates two maps in case whoId or whatId is not populated
	Map<ID, Contact> contactMap = new Map<ID, Contact>([select Id, AccountId from Contact Where Id in :whoIdSet]);
	Map<ID, Account> accountMap = new Map<ID, Account>([select Id, 	Last_Review_Meeting__c, Last_FP_Update__c, Last_IPS_Update__c, 	Last_Tax_Planning_Meeting__c, Last_Tax_Prep_Meeting__c from Account Where Id in :whatIdSet]);

	// The actual Accounts to save
	List <Accounts> Scheduled = new List <Accounts> ();
	List <Accounts> CancelledRescheduled = new List <Accounts> ();


	for(Event e : Trigger.new)
	{
		if(e.whoID != null && contactMap.containsKey(e.whoId))
		{
			//If meeting is scheduled as planned, set this meeting date to the appropriate Last Meeting Date field

			if(e.Status__c != "Canceled" && e.Status__c != "Re-Scheduled")
			{
				Contact c1 = contactMap.get(e.whoId);
				if(c1.AccountId != null)
				{
					Account a1 = c1.AccountId;
					Date d1 = Data.newInstance(e.StartDateTime.year(), e.StartDateTime.month(), e.StartDateTime.day());
					if(e.FSTR__Sub_Type__c == "Tax Preparation Meeting")
					{
						if(d1 > a1.Last_Tax_Prep_Meeting__c)
						{
							a1.Last_Tax_Prep_Meeting__c = d1;
						}
					}
					if(e.FSTR__Sub_Type__c == "Tax Planning Meeting" || Tax_Plan__c == TRUE)
					{
						if(d1 > a1.Last_Tax_Planning_Meeting__c)
						{
							a1.Last_Tax_Planning_Meeting__c = d1;
						}
					}
					if(e.FSTR__Sub_Type__c == "Client Review Meeting")
					{
						if(d1 > a1.Last_Review_Meeting__c)
						{
							a1.Last_Review_Meeting__c  = d1;
						}
					}
					if(e.Financial_Plan_Update__c == TRUE)
					{
						if(d1 > a1.Last_FP_Update__c)
						{
							a1.Last_FP_Update__c = d1;
						}
					}
					if(e.IPS_Updated__c == TRUE)
					{
						if(d1 > a1.Last_IPS_Update__c)
						{
							a1.Last_IPS_Update__c = d1;
						}
					}
					Scheduled.add (a1);
				}
			}
			
			// If meeting is canceled or rescheduled, set appropriate Last Meeting field to last meeting date that was not canceled or rescheduled

			if(e.Status__c == "Canceled" || e.Status__c == "Re-Scheduled")
			{
				
			}
		}
	}
}

Thanks in advance for any help!
William TranWilliam Tran
Why such a complicated trigger for you first trigger?

Advice is to start small and build up to avoid hours of debugging finding the syntax errors like : for(Event e : trigger.net)

for example: start with this, and save;
 
trigger LastEventDate on Event (after insert, after update) 
{

	// The sets used to store the IDs of the Accounts or Contacts/Leads within an event that need to get updated
	Set <Id> whoIdSet = new Set <Id> ();
	Set <Id> whatIdSet = new Set <Id> ();
	}

if that is good: then add this:
 
trigger LastEventDate on Event (after insert, after update) 
{

	// The sets used to store the IDs of the Accounts or Contacts/Leads within an event that need to get updated
	Set <Id> whoIdSet = new Set <Id> ();
	Set <Id> whatIdSet = new Set <Id> ();

	for(Event e : trigger.new)
	{
		if(e.WhoId != null)
		{
			whoIdSet.add(e.WhoId);
		}
		
		if(e.WhatId != null && e.WhoId == null)
		{
			whatIdSet.add(e.WhatId);
		}
	}
}

Then continue to add/save until all you code compiles correctly.

Then you can test to see if does what you expect it to do.

Thx
Sean BarczynskiSean Barczynski
Hi William,

Thanks for the response.  I will definitely heed your advice in the future, but the way I was learning, my process was a little different than it would normally be.  I first laid out the logic as I thought it should be and then converted that to code as I figured out the different pieces.  This code is not final or even intended to compile and run. It still has some of my original "thoughts" that I haven't figured out the correct way to code (see Account a1 = c1.AccountId;).  I just wanted to have a basic construct of the trigger so I could have a layout of what I wanted it to look like and how I wanted it to work.

I appreciate the advice and will certainly use that method in the future, once I'm more comfortable coding in Apex.

Do you have any thoughts on the best practice for the missing piece?