0

This is my class and I am getting this error.

I want to update the same Project record with another status. I wrote the below if in future, which compiled successfully, However, as the records are getting updated again, it calls the future method recursively in the trigger, which is not allowed to call future from future.

One way I can avoid I think is to filter data in the trigger itself. However, don't understand why am I getting this error while compiling which should run fine as I have kept the list outside the method and just adding elements in future, and updating it outside future again.

Any thoughts?

public class BillingCalloutService {
    //Implement business and callout logic methods here
    //

    public List<Project__c> lstToUpdateProj = new List<Project__c>();

    @future(callout=true)
    public static void callBillingService(List<Id> projsId){
        ServiceCredentials__c sc = ServiceCredentials__c.getValues('BillingServiceCredential');
        String username = '';
        String password = '';
        if(sc!=null){
            username = sc.Username__c;
            password = sc.Password__c;
        }

        List<Project__c> lstAllProj = new List<Project__c>([Select Id,Status__c,ProjectRef__c,Billable_Amount__c from Project__c where Id=:projsId]);

        for(Project__c p:lstAllProj){
            if(p.Status__c == 'Billable'){
                BillingServiceProxy.project wrapProj = new BillingServiceProxy.project();
                wrapProj.projectRef = p.ProjectRef__c;
                wrapProj.billAmount = p.Billable_Amount__c;
                wrapProj.username = username;
                wrapProj.password = password;

                BillingServiceProxy.InvoicesPortSoap11 objBill = new BillingServiceProxy.InvoicesPortSoap11();
                objBill.billProject(wrapProj);

                p.Status__c ='Billed';
                lstToUpdateProj.add(p);
            }
        }
    }

    if(lstToUpdateProj.size()>0 && lstToUpdateProj!=null){
        update lstToUpdateProj;
    }
}

Trigger Code

trigger ProjectTrigger on Project__c (after update) {
    //Call the Billing Service callout logic here
    //
    List<Id> lstProjIds = new List<Id>();
    for(Project__c p:Trigger.New){
        lstProjIds.add(p.Id);
    }
    BillingCalloutService.callBillingService(lstProjIds);
}

Test Class:

@isTest
private class BillingCalloutServiceTest {
  //Implement mock callout tests here
    static testMethod void testSuccess(){
        ServiceCredentials__c sc = new ServiceCredentials__c();
        sc.Name = 'BillingServiceCredential';
        sc.Username__c = 'bsUser1';
        sc.Password__c = 'bsPass1';
        insert sc;

        Opportunity opp = new Opportunity(Name='New Opp Test',StageName='Prospecting',Type='New Project',CloseDate=date.today().addDays(20));
        insert opp;

        Project__c proj= new Project__c(Opportunity__c=opp.Id);
        proj.Status__c = 'Running';
        insert proj;

        BillingCalloutServiceMock mock = new BillingCalloutServiceMock();

        Test.startTest();
        Test.setMock(WebServiceMock.class, mock);
            proj.Status__c = 'Billable';
            update proj;
        Test.stopTest();

        System.assertEquals('Billed', proj.Status__c);
    }

    static testMethod void testFailure(){

        ServiceCredentials__c sc = new ServiceCredentials__c();
        sc.Name = 'BillingServiceCredential';
        sc.Username__c = 'bsUser1';
        sc.Password__c = 'bsPass1';
        insert sc;

        Opportunity opp = new Opportunity(Name='New Opp Test',StageName='Prospecting',Type='New Project',CloseDate=date.today().addDays(20));
        insert opp;

        Project__c proj= new Project__c(Opportunity__c=opp.Id);
        proj.Status__c = 'Running';
        insert proj;

        BillingCalloutServiceMockFailure mock = new BillingCalloutServiceMockFailure();

        Test.startTest();
        Test.setMock(WebServiceMock.class, mock);
            proj.Status__c = 'Billable';
            update proj;
        Test.stopTest();

        System.assertEquals('Billed', proj.Status__c);          
    }
}
  • it will good if you put description of the issue and how you are facing this issue. what is your API version? – Santanu Boral May 19 '17 at 15:07
  • 2
    if(lstToUpdateProj.size()>0 && lstToUpdateProj!=null){ (a) You'd get an NPE if the list were null, but (b) this list is never null, so you don't need to check for that condition. Also, it is never necessary to check if a list is empty before performing a DML operation. – sfdcfox May 19 '17 at 15:18
  • Hey, even after filtering out in the trigger, I am getting the same System.AsyncException: Future method cannot be called from a future or batch method: BillingCalloutService.callBillingService(List&lt;Id&gt;) error.. – mvk1991 May 19 '17 at 15:23
  • Did you solve this eventually? I have the same error – Json Aug 1 '17 at 12:25
0

Following observations:

Filter logic before calling future method.

for(Project__c p:Trigger.New){
        //add your filter logic here, so specific changes to be passed for callout
        lstProjIds.add(p.Id);
    }

Instead of using List<Project__c> lstAllProj = new List<Project__c>([Select Id,Status__c,ProjectRef__c,Billable_Amount__c from Project__c where Id=:projsId]);

you can use

List<Project__c> lstAllProj = [Select Id,Status__c,ProjectRef__c,Billable_Amount__c from Project__c where Id=:projsId];

finally, before update, empty and null checking are not needed, straight way use update lstToUpdateProj;

if(lstToUpdateProj.size()>0 && lstToUpdateProj!=null){
        update lstToUpdateProj;
    }

DML and callout are in same transaction. It should not which you have written below.

Test.startTest();
Test.setMock(WebServiceMock.class, mock);
proj.Status__c = 'Billable';
update proj;
Test.stopTest();

You should perform the DML operation before callout. Refer documentation

//perform your DML before callout
Test.startTest();
Test.setMock(WebServiceMock.class, mock);
// check results with assets
Test.stopTest();
  • getting same error in test Classs. updating the test class as well – mvk1991 May 19 '17 at 15:26
  • Specify which line or log you are getting this error – Santanu Boral May 19 '17 at 15:33
  • It's on the line where I am updating the list i.e. update lstToUpdateProj; – mvk1991 May 19 '17 at 16:53

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.