1
votes

I have written an APEX Class that sends an email when a client is released. There is a method that I thought I had bulkified but I was told it does not. This is because this method calls another function which actually does the actual email creation and that is not bulkified. Can someone guide me as to how the SOQL queries can be taken out of the method?

global class LM_ChangeAccountRT {

    private static final Profile sysAdmin = [select id from profile where name='System Administrator'];

@AuraEnabled
    public static String resendEmails(List<String> accountIdList) {
        String response = null;
        try {
            //Only send emails if user is either an ARMS Administor or System Administrator
            if (System.label.ARMS_Administrator_Profile_Id == userinfo.getProfileId() || 
                sysAdmin.Id == userinfo.getProfileId()) {
                List<Account> accList = [SELECT Id,Client_Released__c, RecordTypeId,Client_Number__c, Client_Released__c, Email_Sent__c FROM Account WHERE Id IN:accountIdList];

                for(Account acc: accList){
                    if (acc.Client_Number__c != null && acc.Client_Released__c && acc.Email_Sent__c == true) {
                        sendpdfgenerationEmails(acc); //this is the method thats not bulkified.
                        acc.Email_Sent__c = false; 

                        response = 'Email Sent';
                    }else {
                        response= 'Access Denied';
                    }
                }

                    update accList;
            }  
        }catch(Exception e) {
            System.debug(e.getMessage());
            response = 'Error sending emails';
        }
        return response;
    }

 public static void sendpdfgenerationEmails(Account acc){
        system.debug('start of confirmation card and pdf generation');
        //Logic to find which VF template is used to send an email.
        list<EmailTemplate> templateId = new list<EmailTemplate>();  
        string temppartner;
        String partner_opt_in_attachment;
        boolean sendFCAmail;

        List<Dealership_PDF_Generation__c> custsettingdata = Dealership_PDF_Generation__c.getall().values();
        System.debug('custom setting size = ' + custsettingdata.size());
        // Fetch State
        if(acc.Dealership_State__c!=null && acc.Dealership_Partner__c!=null)
        {
            for(Dealership_PDF_Generation__c tempcustsetting :custsettingdata)

            {   
                if(acc.Dealership_Partner__c == tempcustsetting.Dealership_Partner__c && acc.Dealership_State__c==tempcustsetting.State__c  && tempcustsetting.State__c=='WA' && acc.Dealership_State__c=='WA'){

                    //For WA State
                    // temppartner= '%' + tempcustsetting.TEMPLATE_Unique_name__c + '%';
                    temppartner= tempcustsetting.TEMPLATE_Unique_name__c;
                    if(acc.Dealership_Spiff_Payment__c == '% premium'){
                        partner_opt_in_attachment=tempcustsetting.opt_in_form_premium__c;
                    }else{
                        partner_opt_in_attachment=tempcustsetting.opt_in_form_nonpremium__c;
                    }
                } 
                else if(acc.Dealership_Partner__c == tempcustsetting.Dealership_Partner__c && acc.Dealership_State__c==tempcustsetting.State__c  && tempcustsetting.State__c=='TX' && acc.Dealership_State__c=='TX'){
                    //For TX State 
                    //temppartner= '%' + tempcustsetting.TEMPLATE_Unique_name__c + '%'; 
                    temppartner= tempcustsetting.TEMPLATE_Unique_name__c;
                    if(acc.Dealership_Spiff_Payment__c == '% premium'){
                        partner_opt_in_attachment=tempcustsetting.opt_in_form_premium__c;
                    }else{
                        partner_opt_in_attachment=tempcustsetting.opt_in_form_nonpremium__c;
                    }
                }
                else if(acc.Dealership_Partner__c == tempcustsetting.Dealership_Partner__c && acc.Dealership_State__c!=tempcustsetting.State__c && tempcustsetting.State__c!='TX' && acc.Dealership_State__c!='TX' && acc.Dealership_State__c!='WA' &&tempcustsetting.State__c!='WA' ){
                    //For Non TX State
                    //temppartner= '%' + tempcustsetting.TEMPLATE_Unique_name__c + '%';
                    temppartner= tempcustsetting.TEMPLATE_Unique_name__c;
                    if(acc.Dealership_Spiff_Payment__c == '% premium'){
                        partner_opt_in_attachment=tempcustsetting.opt_in_form_premium__c;
                    }else{
                        partner_opt_in_attachment=tempcustsetting.opt_in_form_nonpremium__c;
                    }
                    system.debug('grabbed template: ' + temppartner);
                }
if(acc.Dealership_Partner__c != null && temppartner!=null ){
            templateId.add([Select id,DeveloperName from EmailTemplate where DeveloperName = :temppartner]); //This will probably cause governor limit issues. First problem

        } 

    if (partner_opt_in_attachment != null) {
                StaticResource sr = [Select  s.Name, s.Id, s.Body From StaticResource s where s.Name =: partner_opt_in_attachment]; //'static_resource' is the name of the static resource PDF. This is another SOQL query that will cause problems

                Blob tempBlob = sr.Body;

                Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
                efa.setBody(tempBlob);
                efa.setFileName('Opt-in.pdf');

                List<Messaging.EmailFileAttachment> attachments = new List<Messaging.EmailFileAttachment>();
                attachments.add(efa);
                // add attachment to each email
                for (Messaging.SingleEmailMessage email : emails) {
                    email.setFileAttachments(attachments);
                }

            }
            system.debug('email sent: ' + emails.size());
            Messaging.sendEmail(emails); 

        }
    } 
}

The reason why I am trying to bulkify this is because I have written a APEX scheduler that calls the resendemails method everyday at 7am to check which records need to have an email sent. I am afraid that if there are more than a 100 clients then it will cause problems and not send the emails. Any suggestions on how I can optimize the sendpdfemailgeenration() method? Thank you

1

1 Answers

1
votes

Yes, you are right - your's resendEmails() method is not bulkified.


Firstly, let me explain you why is that:

  • SOQL to get Accounts
  • Loop 1 on List of Account records
    • Call sendpdfgenerationEmails() method
    • Retrieve list of Dealership_PDF_Generation__c records
    • Loop 2 on List of Dealership_PDF_Generation__c records
      • SOQL to get StaticResources - Very bad! It's inside double loop!
      • Call Messaging.sendEmail() method - Very bad! It's inside double loop!
  • Update on List of Account records

You need to remember that:

1. You should never do SOQLs in loops! - Limit 100 SOQLs per transaction

2. You should never call Messaging.sendEmail() in loops! - Limit 10 calls per transaction


Now let me guide you how to refactor this method:

@AuraEnabled
public static String resendEmails(List<String> accountIdList) {
    // 1. SOQL for List of Account records
    // 2. Retrieve list of Dealership_PDF_Generation__c records
    // 3. SOQL for List of StaticResources for all Names from Dealership_PDF_Generation__c records
    // 4. Declaration of new List variable for Messaging.SingleEmailMessage objects
    // 5. Loop 1 on List of Account records
    //      6. Call new "prepareEmailsForAccount()" method, which prepares and returns list of Messaging.SingleEmailMessage objects
    //      7. Add returned Messaging.SingleEmailMessage objects to list from point 4
    //      8. End of loop 1
    // 9. Call "Messaging.sendEmail()" method with list from point 4
    // 10. Update on List of Account records
}

With this you will avoid SOQLs and calling Messaging.sendEmail() method in loops.