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
phiberoptikphiberoptik 

Trigger and Class to send email alert to Account Owner based on Formula(Date) field value

I need assistance creating a trigger/class combo that would allow me to send time-dependent email alerts to the Account Owner based on the date value in a Formula (Date) field. Basically, I need the email alert to be sent 14, 7, 3, 1, 0 days before the date value in the formula field only if a picklist field contains a specific value. I realize a workflow rule will not work because there is no update on the record due to the date being a formula field. This formula field date value will change once a month, so the cycle of email alerts will restart each month.

 

Do I need a single class that runs daily and fires the trigger's email alert when TODAY() is 14 days before, then again when TODAY() is 7 days before, etc.

 

Or do I need individual classes, one for each planned email alert?

 

I also need the emails to stop when the action is completed by the Account Owner. But then to start back up when the formula field's date changes.

Shailesh DeshpandeShailesh Deshpande
What I would do in this case is create a dummy field on the account record. Have a scheduler that will update the field every 14, 7, 3, 1, 0 days. And write a workflow email alert every time this field is updated. Less work in the scheduler , more use of the point and click functionality just by creating the dummy field.
phiberoptikphiberoptik

Great point! Thank you. I am always looking to use point-click.

 

Would you be so kind as to help me with the scheduler? I am not a developer and my code capabilities are limited at best.

 

 

phiberoptikphiberoptik
I am also wondering what it would take to have a new Extraction record created and related to the Account when TODAY() is 14 days before the Next Extraction Due (formula(date) field value)?
phiberoptikphiberoptik

Here is my starting point...

 

global class AccountExtractionScheduler implements Schedulable
{
global void execute (SchedulableContext ctx)
{
sendEmail();
}
public void sendEmail()
{
if (Account.Next_Extraction_Due__c == System.today().addDays(14))
{
//not sure what to put here as the action to update the Account.Email_Alert_Date__c field with System.today()
}
}
}

 

How do I:

 

1. establish the SObject Account? Right now I get the error: "Error: Compile Error: Comparison arguments must be compatible types: Schema.SObjectField, Date at line 9 column 5".

 

2. edit this to populate TODAY() into the  Account.Email_Alert_Date__c field when TODAY() is 14, 7, 3, 1, and 0 days before Account.Next_Extraction_Due__c field?

OyeCodeOyeCode
Not sure if this best way to implement but let me tell you quick solution to error given here

1. Comparison arguments must compatible type - this means that if are trying to compare two different types of data here

Your field Next_Extraction_Due__c is not (date time it may be date type rather) while System.Now() gives you Date/Time - try running anonymously this code

System. Debug(System.Now() ) ; and then Try running System.Debug(System.Now().addDays(14));

So you are matching datatime with date which is in-compatible


Error 2 :

// first convert field date type to date rather
//Now
if( if (Account.Next_Extraction_Due__c == System.today().addDays(14))
{
//not sure what to put here as the action to update the Account.Email_Alert_Date__c field with System.today()
}

{

// Again make sure Email Alert field is Date type
Email_Alert_Date__c = System.Today();
}

OyeCodeOyeCode

// I have implemented a similar logic in one ot the requirement, attahed is the picture of how i did it without apex code, if I am understanding your problem clearly

 

// These should be steps.

 

// this should be done when the record is created

Step 1 : Develop a workflow rule and match the criteria which should say in condiition 

 

 if(ISPICKVAL( StageName , 'Closed Won') 
,true,false)

 

 

on the same workflow- create time dependent workflow 

 

those should work, other wise Apex scheduler is the other option 

 

 

phiberoptikphiberoptik

Sorry mate. I dont follow.

 

Next_Extraction_Due__c is a Formula (Date) field. I am not referencing System.Now() because I do not want Date/Time. I am referencing System.today() to match Date type to Date.

 

Now, I really just need the scheduler class to just populate System.Today() in the Account.Email_Alert_Date__c when System.Today() is 14 days before Account.Next_Extraction_Due__c, then again when its 7 days before, then again when it is 3 before, then 1 before, then the day of.

 

 

 

OyeCodeOyeCode

I tried running 

 

System.debug(System.today().addDays(14));

 

Here is what I got  -

 

15:04:08:050 USER_DEBUG [1]|DEBUG|2013-02-18 00:00:00

 

 

Try taking the Year, Month, and Day values out of the DateTime variable and pass them into the Date.newInstance() method.

Here is some psuedo-code:

DateTime dT = System.now();
Date myDate = date.newinstance(dT.year(), dT.month(), dT.day());

 

 

phiberoptikphiberoptik

Sorry Mate.. still lost. I am not referencing System.Now() anywhere.

 

How about from scratch, what does the scheduler look like to just populate System.Today() in the Account.Email_Alert_Date__c when System.Today() is 14 days before Account.Next_Extraction_Due__c, then again when its 7 days before, then again when it is 3 before, then 1 before, then the day of. I just need it to run once a day.

kriskkrisk

Phil,

 

So as I understand it here is what you are looking to do

 

You have 2 fields on Account object

 

1) Extraction Due Date field - it could be 02/22/2013 for now and it gets updated everymonth then the cycle restarts

2) Indicator as to whether it is manual extraction or automatic extraction(say a checkbox)

 

So you want to run the scheduler and check the following

 

Is it manual Extraction - if true

 

Is Today() 14 days before Extraction Due Date Field value? 

Or Is Today() 7 days before Extraction Due Date Field value? 

Or Is Today() 3 days before Extraction Due Date Field value? 

Or Is Today() 1 day before Extraction Due Date Field value? 

Or Today() = Extraction Due Date

 

If any of above condition is true - Send a Email reminder

 

If this is your scenario, give me the name of the fields  and their datatypes - field that tracks extraction type and field that tracks Extraction due date. I will provide you the code for Scheduled job.

Shailesh DeshpandeShailesh Deshpande
YOUR SCHEDULER needs to fire once per day. You need to maintain variables in your scheduler class. For eg:
Date day14 = date.today().addDays(-14);
Date day7 = date.today().addDays(-7); and so on.

Then have a soql query that will query all the account records whose date is 14, 7, 3, ...days prior to todays date.

For eg:

LIST<Account> accounts = [Select Id, Name.... From Account where yourDateField =: day14 or yourDateField =: day7 or...]

Then for all the results returned, update the dummy field, ideally checkbox.

For(account acc : accounts)
acc.dummycheckboxfield = true;

HAVE A WORKFLOWRULE that will fire when your dummy field is true. This workflow rule should have 2 actions, one is field update that will change the checkbox back to false and second is the email alert.

NOTE:

1. you can maintian separate lists or maps for accounts whose date is 14, 7 , 3.. Days prior to todays date and also have separate checkboxes for each of the day.

2. It is possibble that you hit the governor limit depending on the number of account records in your org. If that happens, you could move your logic to Batch class and call the batch class from the scheduler.
phiberoptikphiberoptik

Yes this is accurate  krisk, but I was actually planning on the scheduler just populating system.today() in a Date field called Email Alert Date if those date comparisons were True. Then I would use a workflow rule to fire the email. If you think the way you explained it is more efficient, then that is ok with me.

 

Next_Extraction_Due__c - Formula(Date) field

Email_Alert_Date__c - Date field created currently for triggering email alert reminder

Extraction__c - Picklist field with manual values "SCU Manual" and "PRU Manual"

 

kriskkrisk

That is perfect - don't use code if not necessary. So I guess you have it clear now, correct?

phiberoptikphiberoptik

No, I still need code for a class that runs once a day that assess if system.today() is 14, 7, 3, 1, or 0 days before Next_Extraction_Due__c and if TRUE, populate system.today() in the Email_Alert_Date__c field.

 

 

Then once I have that, I have a workflow rule that will fire when Email_Alert_Date__c is updated by the class.

kriskkrisk

I would recommend implementing Batch Apex

 

You need 2 classes. Copy and paste this code into a class you are going to name as UpdateEmailAlertDate and modify the query  in my class for c.SecCon_Checkbox__c = true to change it to the field name extraction_type__c='Manual' or whatever the field value you have.

 

#1) UpdateEmailAlertDate - This class goes through and sets the updates the Email_Alert_Date__c to Today() based on whether you are precisely 14, 7, 3, 1, 0 days away from your Extraction_Date__c



global class UpdateEmailAlertDate implements Database.Batchable<SObject> {

global Database.QueryLocator start(Database.BatchableContext BC){ String query = 'Select c.Name, c.Id From Contact c ' + 'where c.SecCon_Checkbox__c = true and ( c.Extraction_Date__c = NEXT_N_DAYS: 14 or ' + 'c.Extraction_Date__c = NEXT_N_DAYS: 7 or c.Extraction_Date__c = NEXT_N_DAYS: 3 or ' + 'c.Extraction_Date__c = NEXT_N_DAYS: 1 or c.Extraction_Date__c = TODAY)';
return Database.getQuerylocator(query); }
global void execute(Database.BatchableContext BC, List<sObject> scope){ List<Contact> contactList = new List<Contact>(); system.debug('contact size '+scope.size()); for(sObject s : scope){ Contact o = (Contact)s; system.debug('contact name '+o.Name); o.Email_Alert_Date__c = System.today(); contactList.add(o); } update contactList; }
global void finish(Database.BatchableContext BC){ // Get the ID of the AsyncApexJob representing this batch job // from Database.BatchableContext. //Query the AsyncApexJob object to retrieve the current job's information. AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed, TotalJobItems, CreatedBy.Email FROM AsyncApexJob WHERE Id = :BC.getJobId()]; // Send an email to the Apex job's submitter notifying of job completion. Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage(); String[] toAddresses = new String[] {a.CreatedBy.Email}; mail.setToAddresses(toAddresses); mail.setSubject('Apex Sharing Recalculation ' + a.Status); mail.setPlainTextBody ('The batch Apex job processed ' + a.TotalJobItems + ' batches with '+ a.NumberOfErrors + ' failures.'); Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
} }

 

 

#2) ContactUpdateScheduler - Copy the code as is no change necessary on this class

 

global class ContactUpdateScheduler implements Schedulable {
    global void execute(SchedulableContext sc){
        database.executeBatch(new UpdateEmailAlertDate());
    }
}

 

 

#3) Go into Your Name - Setup - Develop - Apex Classes - Schedule Apex

Give a Job name and select the ContactUpdateScheduler to run.

Tip: If you want to run it once, just use Start Date and End Date as the same and choose a time, else run it as frequently as you want.

You can monitor the job using Monitoring Scheduled Jobs and Apex Job