0

Hey guys I have an issue I'm hoping you can help with. I'm a little new to Apex but figuring it out (I think). I have a really awesome unmanaged package that assigns leads/cases and it works great on the lead but I wanted to use it on a custom object. So I thought now problem, I'll just add a trigger for the custom object and modify the other bits to work.

So I built the trigger and it works great and at the end it calls an apex class which should finish off what the trigger started. But the weird thing is the apex class returns nothing in to SOQL query. However when the class is hit again (by the same trigger running again) the SOQL query runs and finds the previous record. It's like the apex class SOQL query is running before the trigger finishes updating. The lead assignment works in the same way and has no issues.

My questions are:

  1. Why is this happening?

  2. Why did the original developer build it this way? Why have the separate APEX class? Couldn't it all be done within the trigger? Just wondering for the sake of learning.

Here is the original trigger that works fine:

trigger FireLeadDistribution on Lead (before insert, before update) {

Set<String> setLeadcriteria= new Set<String>();    
    for ( Lead objLead : Trigger.new)  {        
        setLeadcriteria.add(objLead.distributionValue__c);
    }

    Map<Id, Receiver__c>updtReceivers = new Map<Id,Receiver__c>();
    Map<Id, Distributor__c>updtDistributors = new Map<Id,Distributor__c>();
    List<Id> leadIds = new LIst<Id>();

    Receiver__c[] receiver = [SELECT name,distributor__r.distributioncount__c,distributorstatus__c, id,relateduser__c ,
    distributionValue__c, recordsreceived__c,LastDistributionTime__c,distributor__r.sumofquotas__c,
    first__c,last__c,position__c FROM Receiver__c WHERE distributionValue__c =: setleadcriteria 
    AND Status__c = 'Active' AND UserStatus__c = 'OK' AND DistributorStatus__c = 'Active' AND distributorObject__c = 'Lead'
    ORDER BY distributionValue__c, position__c LIMIT 1000];

    for(Lead lid : trigger.new){

        if(lid.distributionValue__c != null && lid.isDistributed__c == false && lid.isconverted == false ){
            for(integer i=0;i< receiver.size();i++){ // loop through receivers
                if(lid.distributionValue__c == receiver[i].distributionValue__c){

                    Integer leadCount = integer.valueof(receiver[i].distributor__r.distributioncount__c);                  
                    Integer quotasSum = integer.valueof(receiver[i].distributor__r.sumofquotas__c);      
                    Integer remainder = math.mod(leadCount , quotasSum );


                   if(remainder >= receiver[i].first__c && remainder <= receiver[i].last__c ){ 

                       receiver[i].recordsreceived__c = receiver[i].recordsreceived__c+1;
                       receiver[i].distributor__r.distributioncount__c = receiver[i].distributor__r.distributioncount__c+1;

                       receiver[i].LastDistributionTime__c = system.now();

                       lid.receiverID__c = receiver[i].relateduser__c ;
                       lid.isDistributed__c = true ;
                       leadids.add(lid.id);

                       updtReceivers.put(receiver[i].id, receiver[i]);
                       updtDistributors.put(receiver[i].Distributor__c,receiver[i].distributor__r); 

                       break;
                   }
                }


            }//end for "i"
        }    
    }// end for "lid"
    if(updtReceivers.size()>0){
        update updtReceivers.values();
    }
    if(updtDistributors.size()>0){
        update updtDistributors.values();
    }
    if(leadids.size()>0){
        DistributorsAssignment.LeadAssignment(leadids);  
    }   
}

Here is my trigger that also works:

trigger FireOrderItemDistributionPreflight on Order_Item__c (before insert, before update) {

Set<String> setOrderItemcriteria= new Set<String>();    
    for ( Order_Item__c objOrderItem : Trigger.new)  {        
        setOrderItemcriteria.add(objOrderItem.PreflightDistributionValue__c);
    }

    Map<Id, Receiver__c>updtReceivers = new Map<Id,Receiver__c>();
    Map<Id, Distributor__c>updtDistributors = new Map<Id,Distributor__c>();
    List<Id> itemids = new List<Id>();

    Receiver__c[] receiver = [SELECT name,distributor__r.distributioncount__c,distributorstatus__c, id,relateduser__c ,
    distributionValue__c, recordsreceived__c,LastDistributionTime__c,distributor__r.sumofquotas__c,
    first__c,last__c,position__c FROM Receiver__c WHERE DistributionValue__c =: setOrderItemcriteria
    AND Status__c = 'Active' AND UserStatus__c = 'OK' AND DistributorStatus__c = 'Active' AND distributorObject__c = 'Order Item'
    ORDER BY distributionValue__c, position__c LIMIT 1000];

    for(Order_Item__c oid : trigger.new){

        if(oid.PreflightDistributionValue__c != null && oid.isPreflightDistributed__c == false ){
            for(integer i=0;i< receiver.size();i++){ // loop through receivers
                if(oid.PreflightDistributionValue__c == receiver[i].distributionValue__c){

                    Integer OrderItemCount = integer.valueof(receiver[i].distributor__r.distributioncount__c);                  
                    Integer quotasSum = integer.valueof(receiver[i].distributor__r.sumofquotas__c);      
                    Integer remainder = math.mod(OrderItemCount , quotasSum );


                   if(remainder >= receiver[i].first__c && remainder <= receiver[i].last__c ){ 

                       receiver[i].recordsreceived__c = receiver[i].recordsreceived__c+1;
                       receiver[i].distributor__r.distributioncount__c = receiver[i].distributor__r.distributioncount__c+1;

                       receiver[i].LastDistributionTime__c = system.now();

                       oid.PreflightReceiverID__c = receiver[i].relateduser__c ;
                       oid.isPreflightDistributed__c = true ;
                       itemids.add(oid.id);

                       updtReceivers.put(receiver[i].id, receiver[i]);
                       updtDistributors.put(receiver[i].Distributor__c,receiver[i].distributor__r); 

                       break;
                   }
                }


            }//end for "i"
        }    
    }// end for "Oid"
    if(updtReceivers.size()>0){
        update updtReceivers.values();
    }
    if(updtDistributors.size()>0){
        update updtDistributors.values();
    }
    if(itemids.size()>0){
        DistributorsAssignment.ItemPreflightAssignment(itemids);  
    }   
}

Here is the class that both triggers are calling. Works great on the lead but the class doesn't find records on the preflight SOQL query until I run it a second time.

public with sharing class DistributorsAssignment {
    @future 
    public static void LeadAssignment(list<id> leadids ) {

        List<Lead> assignWithoutNotif = new List<Lead>();

        Database.DMLOptions dloNoNotif = new Database.DMLOptions();           
        dloNoNotif.EmailHeader.triggerUserEmail = false;    
        dloNoNotif.EmailHeader.triggerOtherEmail = false;    

        for(Lead lidz : [SELECT Id,ownerid, receiverID__c FROM Lead WHERE isdistributed__c = true AND receiverID__c != NULL]){

                lidz.OwnerId = lidz.receiverID__c ; 
                lidz.receiverID__c = NULL;

                lidz.setOptions(dloNoNotif); 
                assignWithoutNotif.add(lidz);

        }  
       if(assignWithoutNotif.size()>0){          
            database.update(assignWithoutNotif ,dloNoNotif);
        }

    }
    public static void CaseAssignment(list<id> Caseids ) {

        List<Case> assignWithoutNotif = new List<Case>();


        Database.DMLOptions dloNoNotif = new Database.DMLOptions();           
        dloNoNotif.EmailHeader.triggerUserEmail = false;    
        dloNoNotif.EmailHeader.triggerOtherEmail = false;    

        for(Case kasz : [SELECT Id,ownerid, receiverID__c FROM Case WHERE isdistributed__c = true AND receiverID__c != NULL]){

                kasz.OwnerId = kasz.receiverID__c ; 
                kasz.receiverID__c = '';

                kasz.setOptions(dloNoNotif); 
                assignWithoutNotif.add(kasz);

        }  
        if(assignWithoutNotif.size()>0){          
            database.update(assignWithoutNotif ,dloNoNotif);
        }

    }
    public static void ItemPreflightAssignment(list<id> itemIds ) {

        List<Order_Item__c> assignWithoutNotif = new List<Order_Item__c>();

        Database.DMLOptions dloNoNotif = new Database.DMLOptions();           
        dloNoNotif.EmailHeader.triggerUserEmail = false;    
        dloNoNotif.EmailHeader.triggerOtherEmail = false;

        for(Order_Item__c oidz : [SELECT Id,Preflighter__c, PreflightReceiverID__c FROM Order_Item__c WHERE isPreflightDistributed__c = true AND PreflightReceiverID__c != NULL]){

                oidz.Comments__c = 'test' ;
                oidz.Preflighter__c = oidz.PreflightReceiverID__c ;
                oidz.PreflightReceiverID__c = NULL;

                oidz.setOptions(dloNoNotif); 
                assignWithoutNotif.add(oidz);

        }
        if(assignWithoutNotif.size()>0){          
            database.update(assignWithoutNotif ,dloNoNotif);
        }

    }

    public static void ItemSenderAssignment(list<id> Itemids ) {

        List<Order_Item__c> assignWithoutNotif = new List<Order_Item__c>();


        for(Order_Item__c Oidz : [SELECT Id,Sender__c, SenderReceiverID__c FROM Order_Item__c WHERE isSenderDistributed__c = true AND SenderReceiverID__c != NULL]){

                Oidz.Sender__c = Oidz.SenderReceiverID__c ; 
                Oidz.SenderReceiverID__c = NULL;


        }

    }

}

Finally here is a debug log (to long to post): https://docs.google.com/document/d/1EY7-Mgd1UMrhsvh_a4Ka7xu5gSpTLJHERxjjO4kq4I4/edit?usp=sharing

  • 2
    Hi Jake, welcome to SFSE. This is a large amount of code and information to look through without a lot of clarity. I'd suggest if you can that you cut down your code to just the pieces you're working on right now (we probably don't need the other triggers), and include the elements of the log that you believe illustrate the problem. A little more detail on the sequence of operations that causes your issue might also be helpful. – David Reed Jan 8 at 15:15
  • This can probably answer your question as to why the developer used a different class. It's worth noting that not all developers think this way. I tend not to blindly follow what other people say architecture wise and this is no exception although I do agree with most of what is said here. – gNerb Jan 8 at 15:32
  • David thanks for the suggestions, I'll keep those in mind going forward! gNerb, I'll give the link a read through, as a mostly self taught admin I always try to make sure I'm learning the proper way to do things. I appreciate the link! – Jake Bullard Jan 8 at 15:59
4

The old method LeadAssignment is annotated with @future, whereas your new method ItemPreflightAssignment is NOT.

You might want to check out the details on what @future does here, but in short:

  • a method annotated with @future will be called outside the transaction context (i.e., the trigger runs, schedules the LeadAssignment call, finishes the trigger and commits the transaction to the database and then LeadAssignment will be executed asynchronously in a new transaction)
  • the reason the original developer was using a separate class was so they could use the @future annotation on the method (you couldn't syntactically put that into the trigger itself)
  • since your method is no @future you're still in the same transaction as the trigger -- and since it's a before tigger, the record is not yet committed to the database when the query runs (so the query doesn't return it -- remember in the @future case of Lead Assignment your are in a separate later transaction)
  • your trigger/method work the second time around (on an update), since then there is something in the database from the previous insert. But note that the query reads old data (i.e., does not see any new modifications that the trigger may or may not have made).

In short, put @future in front of your new method (the other ones as well) and they should behave the same as the original method.

  • Thank you Miichi that indeed was exactly what the problem was! I appreciate your help! – Jake Bullard Jan 8 at 15:56

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.