0

I have to write a class that accepts input from a trigger. This class checks "DBD_ID" when users are trying to create a new lead. If the condition is not correct, then throw an error message. If the condition is correct, they can create and save a new lead, and the "business type" field of the lead will be automatically updated according to the master object. I don't know how to update the "business type" field, and the error messages are shown as "We hit a snag." instead. Please help me!

1.LeadHandler.apxc

    public class LeadHandler {

    public static void CheckDBD(List<Lead> newLeads) {
        
        //LeadHandler.CheckDBD([select Name, DBD_ID__c from Lead]);  **execution code
        
        //List<String> dbdid = new List<String>();
        List<List<String>> dbdid = new List<List<String>>();
        //List<String> pass = new List<String>();
        List<List<String>> pass = new List<List<String>>();
        List<List<String>> dbdprivate = new List<List<String>>();
        List<List<String>> dbdpublic = new List<List<String>>();
        
        List<Lead> testLead = new List<Lead>();
        
        Integer count_private = 0;
        Integer count_public = 0;
        
        DBD_Info__c[] dbdinfo_private = [select Type__c, starting_number__c, End_number__c 
                                         from DBD_Info__c order by Type__c];
        DBD_Info__c[] dbdinfo_public = [select Type__c, public_co_number__c 
                                         from DBD_Info__c order by Type__c];
        
        //keep dbd_id for each lead
        for(Lead lead : newLeads) {
            //dbdid.add(lead.DBD_ID__c);
            dbdid.add(new List<String>{String.valueOf(lead.Name),
                String.valueOf(lead.DBD_ID__c), String.valueOf(lead.Business_Type__c)});
        }
        
        //keep public_co_number__c
        for(DBD_Info__c dbdpub : dbdinfo_public){
            dbdpublic.add(new List<String>{String.valueOf(dbdpub.Type__c),
                String.valueOf(dbdpub.public_co_number__c)});
        }
        system.debug(dbdpublic);
        
        //keep private dbdid
        for(DBD_Info__c dbdpri : dbdinfo_private){
            dbdprivate.add(new List<String>{String.valueOf(dbdpri.Type__c),
                String.valueOf(dbdpri.starting_number__c),
                String.valueOf(dbdpri.End_number__c)});
        }
        system.debug(dbdprivate);
        
        //check condition for input dbdid
        for(List<String> x : dbdid){
            //reject if empty (for debugging, we continue)
            if(String.isEmpty(x[1])){
                //continue;
                //string is empty, throw an error here
                newLeads[0].DBD_ID__c.addError('Please input your DBD ID');
               
            }
            //check length of input dbdid = 5
            if(x[1].length()==5){
                system.debug('pass = '+x);
                pass.add(new List<String>{String.valueOf(x[0]),
                String.valueOf(x[1]),String.valueOf(x[2])});
                
                
            }
            else{
                //not pass the requirement, throw an error here
                newLeads[1].addError('Invalid DBD ID');
            }
        }
        
        //check public or private
        for(List<String> y : pass){
            //check private, if first letter is number
            if(y[1].substring(0,1).isNumeric()){
                system.debug(y+' = private');
                for(List<String> m : dbdprivate){
                    //compare input dbd in the dbd information
                    if(y[1]>=m[1] && y[1]<=m[2]){
                        system.debug('in the range'+m[1]+' '+m[2]);
                        //then specify type to m[0]
                        system.debug('type = '+m[0]);
                        count_private = 0; //reset to zero
                        
                        
                        //update business type to m[0]
                        
                        break;
                    }
                    else{
                        system.debug('not in the range ');
                        system.debug(count_private);
                        count_private += 1;
                    }
                    if(count_private == 21){
                        //system.debug('your dbd id is not in any range');
                        //error not match in the master, throw an error here
                        newLeads[1].addError('your dbd id is not in any range');
                    }
                }
                
            }
            //check public
            else{
                system.debug(y+' = public');
                system.debug(dbdpublic);
                for(List<String> n : dbdpublic){
                    //compare input dbd in the dbd information
                    if(y[1].Contains(n[1])){
                        system.debug('yes '+y+'='+n[1]);
                        system.debug('type = '+n[0]);
                        count_public = 0; //reset to zero
                        
                        //update business type to n[0]
                        
                        
                        break;
                    }
                    else{
                        system.debug('no');
                        system.debug(count_public);
                        count_public += 1;
                    }
                    if(count_public == 21){
                        system.debug('not match');
                        //error not match in the master, throw an error here
                        newLeads[1].addError('your dbd id is not in the master');
                    }
                }
            }
        }
    }   }

2.LeadTriggerHandler.apxc

    /**
     * @description Lead trigger implementation class
     */
    public with sharing class LeadTriggerHandler implements ITriggerHandler {
        public static Boolean TriggerDisabled = false;
        public Boolean isDisabled() {
            return TriggerDisabled;
        }
        public void beforeInsert(List<SObject> newItems) {
            LeadHandler.CheckDBD(newItems);
        }
        public void beforeUpdate(Map<Id, SObject> newItems, Map<Id, SObject> oldItems) {
        }
        public void beforeDelete(Map<Id, SObject> oldItems) {
        }
        public void afterInsert(Map<Id, SObject> newItems) {
        }
        public void afterUpdate(Map<Id, SObject> newItems, Map<Id, SObject> oldItems) {
            //LeadHandler.CheckDBD(newItems.values());
        }
        public void afterDelete(Map<Id, SObject> oldItems) {
        }
        public void afterUndelete(Map<Id, SObject> oldItems) {
        }
    }

3.LeadTrigger.apxt

    /**
     * @description trigger for Lead
     */
    trigger LeadTrigger on Lead(
        before insert,
        before update,
        before delete,
        after insert,
        after update,
        after delete,
        after undelete
    ) {
        TriggerDispatcher.run(new LeadTriggerHandler());
    }

2 Answers 2

0

newLeads are the leads coming in from a DML transaction. If you're using the UI to create/edit a lead, then newLeads will contain only one value. This means that newLeads[1] will throw a ListException (index out of bounds), because there is only one element to work with.

Ultimately, you're going to need to completely rewrite your code, because you have several glaring problems. You're querying the DBD_Info__c table twice, querying every record in the database. That's bad logic. If this is a Custom Setting or Custom Metadata, use the getAll method to get the values to check against. If this is a Custom Object, you should build an appropriate list of values to filter against.

Don't use variable names like x, y, n, and m, as they are not descriptive and make the code more difficult to read. Why are you accessing x[1] for a given check? It's just unclear without jumping through some mental gymnastics.

Why are you using String.valueOf everywhere? It appears that these fields are already String values, you're just making the code more difficult to read with no apparent benefit.

The number 21, what is that supposed to represent? I'm guessing that's how many DBD_Info__c records you have, but what if that ever changes? Someone's going to have to maintain this code every time a database value changes.

Your code is not properly bulkified. It should be able to handle a list of any number of records in newLeads, which means looping through each lead, performing your calculations, then moving on to the next.

Note that if you use addError, that record will not be saved. You can't both add an error and update a field, which doesn't seem to be in your code anywhere anyways.

You also have several nested loops that are a bad idea. Presuming your list of DBD_Info__c records have 21 records in them, That means that you need a total of 441 loops per lead as designed right now. I'm not entirely sure what you're trying to do here, but this logic doesn't seem to make much sense.


Your code should be designed with an aggregate-query-update pattern(my old blog post). First, gather together all the values you need from all the leads in newLeads. Then, query the DBD_Info__c to get just the values that you need to validate against. Finally, loop over all the leads a second time to determine which records have errors, if any.

Avoid hardcoding values like 21, 0, and 1. None of these numbers are appropriate in your code, because you should be working against the size of the lists of records you have in memory. Proper bulkification of your code involves handling every record in newLeads, not just a single record.

0

First go to setup - Debug Logs, click the New button to create a new debug log, then run your app to pinpoint where the issue arises.

Also sfdcfox is right that you need to avoid throwing error in a for loop. Actually this can be a common rule in other languages, i.e., never throw exception within a loop. Instead, catch the exception, add it to a collection and continue the loop. After the loop ends, check the error collection and throw exception there. Because if you throw exception in a loop, records that won't throw exception would be skipped. Or there might be multiple wrong records in the loop. If you throw exception upon the first wrong record, you can't find all the wrong records in one shot and would have to fix your data multiple times.

You must log in to answer this question.

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