function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Laurie DrewLaurie Drew 

Issue with Batch Apex job

I have a batch apex job that basically goes through all invoices and totals the amounts for each sales person for each month and year.  The job works as expected in the sandbox environment with the test data I created.  But when I moved the job to production, it runs without errors, but does not update the fields with the monthly invoice sum totals like it does in sandbox.  In reviewing the logs I found one for example that found totals and shows that it updated the fields for the months.  Then in the very next log that did not find any invoices with totals, it updated the fields with null values for the very same records as in the prior log.  The Forecast and Forecast detail objects were created from scratch for this batch job and have no other triggers or processes running against them to udpate any fields.  My code is below, can anyone see why it is not updating the sum fields properly?

global with sharing class Forecast_Batch implements Database.Batchable<sObject>, Database.Stateful{

        global Database.QueryLocator start(Database.BatchableContext BC)
        {
            return Database.getQueryLocator([SELECT Id,OwnerId FROM Account]); //Query all accounts for ID and OwnerId
        }

    global void execute(Database.BatchableContext BC, List<SObject> scope)
    {        
        Map<Id, Map<String,Decimal>> accountAmountMap = new Map<Id,Map<String,Decimal>>();

        List<Id> accountOwnerIds = new List<Id>();
        Set<Id> accountIds = new Set<Id>();
        
        system.debug('+++ SCOPE SIZE ' + scope.size());
        
        for (SObject s : scope) {
            
            Account acc = (Account)s;
            if(!accountIds.contains(acc.Id)){
                accountIds.add(acc.Id);
            }
            
        }
        
        for (Account acc : [SELECT OwnerId,(SELECT Amount__c,InvoiceDate__c,OwnerDetails__c,Inv_Yr__c FROM Invoice__r ) FROM Account WHERE Id in : accountIds]) {
            
            Map<String, Decimal> amountMap = new Map<String, Decimal>();
            
            for (Invoice__c inv : acc.Invoice__r) {
                 
                Decimal amount = amountMap.get(inv.OwnerDetails__c);
                if (amount != null) {
                    amountMap.put(inv.OwnerDetails__c, inv.Amount__c + amount); 
                } else {
                    amountMap.put(inv.OwnerDetails__c, inv.Amount__c); 
                }
            }
            accountAmountMap.put(acc.Id, amountMap);
            accountOwnerIds.add(acc.OwnerID);
            
        }
        System.debug(accountOwnerIds);

         // Query list of forecast details record based on Account's owner Id

        List<Forecast_Details__c> forecastdetails = [SELECT ID,Name,Month_Total__c,OwnerID__c,FDOwnerDets__c from Forecast_Details__c where OwnerID__c IN : accountOwnerIds];

        // Iterate accounts in for loop
        // iterate forecast details record
        // get invoice amount based on account id and forcast month.
        // update in forecast detail record.

        for (SObject s : scope) {
            Account acc = (Account)s;
            Map<String, Decimal> amountMap = accountAmountMap.get(acc.Id);
            for (Forecast_Details__c forecastDet : forecastdetails) {
                if (forecastDet.OwnerID__c == acc.OwnerId)
                    
                {
                    Decimal amount  = amountMap.get(forecastDet.FDOwnerDets__c);  
                    forecastDet.Month_Total__c = amount;
                    System.debug('match');
                    System.debug(amount);
                }
            }
        }
        System.debug(forecastdetails);
        update forecastdetails;
    }  

    global void finish(Database.BatchableContext BC){}



I really appreciate any assistance that anyone can provide!
Best Answer chosen by Laurie Drew
Abdul KhatriAbdul Khatri
As a quick check, can you please take a look at the permissions on the required field that is causing issues.

In other notes, I see many issues with the code from the efficiency perspective.
  • First you are running for all Accounts, even though it is batch I would suggest to restrict the Account with some possible filters. 
  • Others you are running for loop for all, please try to use aggregate SOQL 
  • What is the difference between the Account Owner and the Owner on the Invoice as I do see later for forecase you are getting the amount using the Account Ownerid where to store Invoice OwnerDetailId.

Well please check out my very first point of permission, if that works then you should be good. And if you are interested in refactoring the code we can work on that.

All Answers

Abdul KhatriAbdul Khatri
As a quick check, can you please take a look at the permissions on the required field that is causing issues.

In other notes, I see many issues with the code from the efficiency perspective.
  • First you are running for all Accounts, even though it is batch I would suggest to restrict the Account with some possible filters. 
  • Others you are running for loop for all, please try to use aggregate SOQL 
  • What is the difference between the Account Owner and the Owner on the Invoice as I do see later for forecase you are getting the amount using the Account Ownerid where to store Invoice OwnerDetailId.

Well please check out my very first point of permission, if that works then you should be good. And if you are interested in refactoring the code we can work on that.
This was selected as the best answer
Laurie DrewLaurie Drew
I have verified that the permissions on the Monthly total field are set to editable by all profiles but the field is not being updated. 

The query needs to run on all Accounts as the matching criteria is that each Salesperson owns their own Forecast records (these are by year), and Account record, I am then querying the invoice object for all invoices for each account, then if each invoice has an invoice amount, sum those amounts for each month and update the Monthly total field on the Forecast Detail record (this is each month of the year, related to each year at the Forecast level).  So Salesperson John Doe has a Forecast record for 2019, Forecast Detail records for January - August of 2019, I need to query through all accounts that are owned by John Doe, find all invoices for that Account and get the Invoice Amount, then sum the amounts for each month and write that total to the Monthly total field on the Forecast Detail record for that month.

Thank you for your assistance!
Abdul KhatriAbdul Khatri
My Question was,

Will there be an Account owned by Sales Person having invoice that is owned by a different Owner of the same account? I mean in brief, Is the Account owner will always be the same to Inovice owner for that Account?
Laurie DrewLaurie Drew
Yes the Account Owner and Invoice Owner will always be the same.
Abdul KhatriAbdul Khatri
Can you please share the log and see if you can match and amount as you are printing them?