0

I'm trying to update a field on the account field with a trigger using after insert and update. I am using a future method to make a callout to a rest API to get the rate of BTC in USD.

My issue is that I am getting this error when I try to execute a DML statement within the future method.

The error: FATAL_ERROR System.DmlException: Update failed. First exception on row 0 with id 0016800000UlQ04AAF; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, AccountTrigger: execution of AfterUpdate

The trigger handler calls the callFutureMethod() method which in turn calls the method that executes the callout to the API.

Class & methods that make the callout to the API:

public static List <Account> accountsWithAlteredRevenueList = new List <Account>();
public static Set <Id> accountIdsSet = new Set <Id>();
//AFTER
public void getAccountsFromTrigger(Account account) {
    if (!accountIdsSet.contains(account.Id)) {
        accountsWithAlteredRevenueList.add(account);
        accountIdsSet.add(account.Id);
        system.debug('ADDED IN ACCOUNT');   
    } else {
        system.debug('ALREADY IN THERE');
    }
}

public static void callFutureMethod() {
    String serialised_list = JSON.serialize(accountsWithAlteredRevenueList);
    getDefaultCurrencyRateInBTC(serialised_list);
}

@future(callout=true)
public static void getDefaultCurrencyRateInBTC(String serialised_list){
    Decimal rate = 0;
    HttpRequest req = new HttpRequest();
    req.setEndpoint('https://bitpay.com/api/rates');
    req.setMethod('GET');
    HttpResponse res = new Http().send(req);
    List<Object> all_currency_info = new List<Object>();
    if (res.getStatusCode() == 200) {
        List<Object> response_data = (List<Object>) JSON.deserializeUntyped(res.getBody());
        for (Object obj : response_data) {
            all_currency_info.add(obj);
        }
    }
    for (Object single_currency : all_currency_info) {
        Map<String, Object> currencies_map = (Map<String, Object>)single_currency;
        if (currencies_map.containsKey('rate') && currencies_map.get('code') == 'USD') {
            rate = (Decimal)currencies_map.get('rate');
            defaultRate = rate;
            CalculateAnnualRevInBTC.annualRevInBTC(serialised_list, defaultRate);
            break;
        }
    }
} 

This is the method that is called within the future method to execute a DML action.

public static void annualRevInBTC(String serialised_list, Decimal rate) {
    List <Account> update_revenues = new List <Account>();
    List <Account> deserialised_account_list = deserialiseList(serialised_list);

    for (Account acc : deserialised_account_list) {
        acc.Annual_Revenue_Bitcoin__c = (acc.AnnualRevenue / rate).setScale(8);
        //After
        update_revenues.add(acc);
    }
    //AFTER
    if (!update_revenues.isEmpty()) {
        update update_revenues;
    }
}

Any suggestions that can help me avoid this error will be welcome. Thanks in advance!

1 Answer 1

0

It would be better if you set debug logs and analyze the error.

from the code what i can see that you are calling a future method from account trigger and account updates is also done in future method which will in turn call trigger and invoke future method again which will cause error as "you cannot call future method from another future method or batch class".

wherever you are calling future method , check the context that it is not getting called from future or batch method. something like this;

if(! system.isFuture() && ! system.isBatch()){
getDefaultCurrencyRateInBTC(serialised_list);
}
1
  • 1
    Thanks for your suggestion! This solution worked, I changed around the structure of the code and I got no new errors!
    – Carraig
    Commented Jun 6, 2023 at 9:32

You must log in to answer this question.

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