You need to sign in to do that
Don't have an account?
Laurie 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!
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!
In other notes, I see many issues with the code from the efficiency perspective.
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
In other notes, I see many issues with the code from the efficiency perspective.
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.
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!
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?