2

I'm new to development and trying to edit a trigger handler class for the account. At the moment we only need anything triggered after update I believe. This is what the class looks like at the moment, which works:

public with sharing class AccountTriggerHandler extends TriggerHandler {
    public override void afterUpdate() {

        CaseEntitlementHandler.accountEntitlementsIsChanging((Map<Id, Account>)trigger.oldMap, (List<Account>)trigger.new);
    }
}

Now I need to send an email to a specific set of contacts associated to an account where they have 60 days left on their contract (and then 30 and 15, but one thing at the time). The contract end date is captured on a date field called Customer End Date. I couldn't find a better way to do this than using the trigger, but do let me know if it's possible to do this declaratively. Here is what it looks like now:

public with sharing class AccountTriggerHandler extends TriggerHandler {

    public override void afterUpdate() {
        CaseEntitlementHandler.accountEntitlementsIsChanging((Map<Id, Account>)trigger.oldMap, (List<Account>)trigger.new);
    }

    @InvocableMethod public static void sendEmail(List<Account> customerEndDateList) {
        for (Account acc : Trigger.new){
            date d = system.today().addDays(-60);
            List<Account> customerEndDateList2 = [SELECT Id, Name, Customer_End_Date__c, Paid_Devices__c, RADAR_Account_Status__c 
                                         FROM Account 
                                         WHERE Customer_End_Date__c = :d
                                         AND Current_Reseller__c != 'Company1' 
                                         AND Current_Reseller__c != 'Company2' 
                                         AND Current_Reseller__c != 'Company3'
                                         AND Paid_Devices__c <= 499
                                         AND RADAR_Account_Status__c = 'Paying'
                                         AND Type = 'Customer'];
            System.debug('customerEndDateList2 = ' + customerEndDateList2); 

            List<Messaging.SingleEmailMessage> emailsToSend = new List<Messaging.SingleEmailMessage>();

            List<Contact> contactsToEmail = [SELECT Id, Name
                                     FROM   Contact
                                     WHERE  (RADAR_Administrator__c = 'Customer Admin'
                                     OR RADAR_Administrator__c = 'Parent Admin')
                                     AND AccountId = acc.Id)];
                                     System.debug('contactsToEmail = ' + contactsToEmail);
            Id templateId = [SELECT Id, Name 
                     FROM   EmailTemplate 
                     WHERE  Name = 'End of Contract 60 days Alert'].Id;

            for(Contact con: contactsToEmail ){
                Messaging.SingleEmailMessage email = new messaging.SingleEmailMessage();
                email.setTemplateId(templateId);
                email.setTargetObjectId(con.Id);
                email.setSaveAsActivity(true); 
                email.setSenderDisplayName('Wandera Sales Operations'); //Here if you want to change the sender name
                emailsToSend.add(email);

            }
            Messaging.sendEmail(emailsToSend);   
        }
    }
}

But I'm getting the following errors:

Unexpected token 'acc.Id'. (Line: 33, Column: 54)
Invalid loop variable type expected SObject was Account (Line: 13, Column: 5)

Any help on this would be much appreciated. I want to make sure that the trigger still does what it's doing at the moment and also that it will actually send the email 60 days before the end date. I haven't been able to test it yet because I can't get it to save!

2
  • shouldnt you be using :acc.Id instead of acc.Id ? to dynamically bind the value in your SOQL (missing colon)
    – glls
    Jul 18, 2018 at 13:51
  • Also, you have a SOQL inside the for loop, you should avoid SOQLs and DMLs inside for loop.
    – Jarvis
    Jul 18, 2018 at 13:54

1 Answer 1

2

@InvocableMethod is not something you generally see in trigger handlers because it has nothing to do with the trigger itself. That's a method you can call from Process Builder, where you should be building this time-dependent action flow. Triggers don't themselves do time-dependent actions; they fire only on changes to the record.

You should not do this in your invocable method:

for (Account acc : Trigger.new){

because that invocable method shouldn't be dependent on a trigger context. Instead, you should be iterating over the method's parameter customerEndDateList.

There may be other issues here because of the mixing of trigger and invocable action semantics. I would factor that invocable method out into a separate class.

You're receiving an error on acc.Id because you're missing an Apex bind colon : before it, which is required to reference Apex variables in SOQL.

2
  • ok, that makes sense. Would you say that I'm better off doing this on Process Builder where a change in the customer end date would trigger a scheduled action with the apex class that contains the invocable method? And if the customer end date changes, it should unschedule the previous actions scheduled? @David
    – Priscila
    Jul 18, 2018 at 14:04
  • 2
    I would say that you pretty nearly must do it that way. The only way to get time-dependent functionality in a trigger is to have the trigger fired by a time-dependent action anyway. It's much more natural to cut out the middleman. And yes, changes to the end date will schedule/unschedule actions appropriately.
    – David Reed
    Jul 18, 2018 at 14:08

You must log in to answer this question.

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