+ Start a Discussion
Kristen Aldrich 14Kristen Aldrich 14 

Problem with Apex execution method?

I received the following message (below) about a Flow error and am having a hard time deciphering what action steps I need to take to fix this. It seems to lie in an Apex class or trigger. For context, we use Click & Pledge for payment processing online which creates Opportunities in Salesforce. SF support got as far as identifying the issue is our custom trigger: CandP_OpportunityLineItemProcess in method executeOLIAllocationProcess. But we don't have Premier support so they can't tell me anything more nor what needs to be altered. Here is the information from the email notification:

Error element myRule_1_A1 (FlowActionCall).
An Apex error occurred: System.AsyncException: Future method cannot be called from a future or batch method: CandP_OpportunityLineItemProcess.executeOLIAllocationProcess(Set)
________________________________________
Flow Details
Flow API Name: Opp_Product_PB
Type: Record Change Process
Version: 1
Status: Active
Org: Appalachian Mountain Club (00D50000000cBTw)
Flow Interview Details
Interview Label: Opp_Product_PB-1_InterviewLabel
Current User: Rachel Sensenig (00550000007yb9w)
Start time: 9/25/2019 11:25 AM
Duration: 0 seconds
How the Interview Started
Rachel Sensenig (00550000007yb9w) started the flow interview.
Some of this flow's variables were set when the interview started.
myVariable_old = null
myVariable_current = OpportunityLineItem (00k2J00000lKASwQAO)
ASSIGNMENT: myVariable_waitStartTimeAssignment
{!myVariable_waitStartTimeVariable} Equals {!$Flow.CurrentDateTime}
Result
{!myVariable_waitStartTimeVariable} = "9/25/2019 11:25 AM"
DECISION: myDecision
Outcome executed: myRule_1
Outcome conditions:
{!myVariable_current.Opportunity.Integration_Source__c} (Click and Pledge) Equals Click and Pledge
CANDP_OPPORTUNITYLINEITEMPROCESS (APEX): myRule_1_A1
Inputs:
oppLineIds = {!myVariable_current.Id} (00k2J00000lKASwQAO)
________________________________________
Error Occurred: An Apex error occurred: System.AsyncException: Future method cannot be called from a future or batch method: CandP_OpportunityLineItemProcess.executeOLIAllocationProcess(Set)
________________________________________
________________________________________
Salesforce Error ID: 1315178525-18218 (-271902632)


Please help!
Khan AnasKhan Anas (Salesforce Developers) 
Hi Kristen,

Greetings to you!

You have a future method in a class that is calling another future method.
You cannot call the future method from another future method. This is a platform limitation. If an @future method could be called from another @future method, one could have a chain of indeterminate length or even create a loop that would extend the execution a transaction indefinitely through a very complex maze of additional execution contexts. Tracing the transaction to completion could become very complex. This would be what's considered an "anti-pattern".

Reference: 
https://salesforce.stackexchange.com/questions/184948/future-methods-cannot-be-called-from-another-future-method

https://salesforce.stackexchange.com/questions/204896/calling-async-from-async-process

I hope it helps you.

Kindly let me know if it helps you and close your query by marking it as solved so that it can help others in the future. It will help to keep this community clean.

Thanks and Regards,
Khan Anas
Kristen Aldrich 14Kristen Aldrich 14
Hi Khan! This is very helpful information and the links to the stack exchange are useful as well. However, I am not a developer and still don't know what I need to do to correct the code to ensure this error no longer occurs. Do I simply swap out the @future in the Apex Class for something else? What needs to change in the code? I'm copying and pasting the apex class CandP_OpportunityLineItemProcess below. Is that the code that needs to be adjusted or should I adjust something else that this code is referencing? Additional guidance would be greatly appreciated!
 
public class CandP_OpportunityLineItemProcess {
  
  //private static Set<Id> oppIds {get;set;}
  //private static Set<Id> pbeIds {get;set;}
  //private static Map<Id,Opportunity> oppMap {get;set;}
  //private static Map<Id,PricebookEntry> pbeMap {get;set;}
  private static Map<Id,OpportunityLineItem> oliMap {get;set;}
  private static List<npsp__Allocation__c> oliAllocations {get;set;}

  
  @InvocableMethod(label='Create GAUs From Opp Products' Description='On Insert Create the allocation for this Opp from the Opportunity Prodcut')
  public static void executeOLIAllocationProcess(List<Id> oppLineIds)
  {
    CandP_OpportunityLineItemProcess.executeOLIAllocationProcess(new Set<Id>(oppLineIds));
  }
  @Future
  public static void executeOLIAllocationProcess(Set<Id> oliIds){
    //prepareOLIData(newOlis);
    //getOppMap();
    //getPBeMap();
    CandP_OpportunityLineItemProcess.oliAllocationProcess_Batch(oliIds);
    
  }
  public static void oliAllocationProcess_Batch(Set<Id> oliIds)
  {
    getOLiMap(oliIds);
    processCnP_OLI(oliMap.values());
    commitOliAllocations();
  }

  private static void getOliMap(Set<Id> oliIds){
    oliMap = OpportunityLineItemHelper.getOLiMap(oliIds);
  }

  private static void processCnP_OLI(List<OpportunityLineItem> newOlis){
    oliAllocations = new List<npsp__Allocation__c>();
  
    for(OpportunityLineItem oli: newOlis){
      //If we have a PricebookEntry with a GAU Allocation
      if(oli.PricebookEntry.General_Accounting_Unit__c != null)
      {
        oliAllocations.add(GAUAllocationHelper.createAllocationForOpportunity(oli.PricebookEntry.General_Accounting_Unit__c,
                        null,oli.TotalPrice,oli.Opportunity.AccountId,oli.OpportunityId));
      }
    }
    System.debug('Oli Allocations: '+ oliAllocations);
  }
  
  private static void commitOliAllocations(){
    if(!oliAllocations.isEmpty()){
      try{
        insert oliAllocations;
      }catch(Exception ex){
        System.debug('Error on Oli Allocation Create: '+ex.getMessage()+'. Stack Trace: '+ex.getStackTraceString());
      }
    }
  }


}

 
Kristen Aldrich 14Kristen Aldrich 14
Hi again Khan and the greater community! Hoping to get some help and guidance on how to correct this code. I'm still getting occasional errors and would love to fix this! I've read a bit about using Queueable Apex but I'm still unclear exactly how to update my code.