Scenario: Enhanced Requirements for Interest Calculation on Account Balances
Overview
The goal is to automate the calculation and distribution of daily interest for accounts based on the total amount associated with their related opportunities. This will ensure that each account’s balance is updated with accrued interest and that each opportunity reflects its portion of the interest.
Requirements
- Custom Field Creation:
- Field Name:
Account_Amount__c
(Type – Currency) - Field Name:
No_Of_Opp__c
(Type – Number) - Description:
Account_Amount__c
field on the Account object will hold the total balance derived from the sum of all associated Opportunity amounts andNo_Of_Opp__c
field on Account object will hold the total count of number of Opportunity record associated with the Account.
- Field Name:
- Interest Calculation:
- Interest Rate: 1% daily
- Interest Calculation Formula:
- Daily Interest =
Account_Amount__c * 0.01
- Daily Interest =
- Process:
- Retrieve the current balance from the
Account_Amount__c
field. - Calculate the daily interest as 1% of the current balance.
- Update the
Account_Amount__c
with the new balance, which includes the calculated interest.
- Retrieve the current balance from the
- Interest Distribution:
- Distribution Method:
- Split the total daily interest equally among all related Opportunities.
- Process:
- Retrieve all Opportunities associated with the Account.
- Divide the total daily interest by the number of related Opportunities to determine the interest amount to be added to each Opportunity.
- Update each Opportunity’s amount with the calculated interest.
- Distribution Method:
- Batch Job Scheduling:
- Frequency: Every 24 hours
- Job Details:
- Create a scheduled batch job to perform the following tasks daily:
- Calculate the daily interest based on the current
Account_Amount__c
. - Update the
Account_Amount__c
with the new balance including interest. - Distribute the daily interest equally among related Opportunities and update their amounts accordingly.
- Calculate the daily interest based on the current
- Create a scheduled batch job to perform the following tasks daily:
- Implementation Steps:
- Custom Field Creation:
- Add fields
Account_Amount__c
andNo_Of_Opp__c
to the Account object.
- Add fields
- Batch Apex Class:
- Develop an Apex Batch class to handle the interest calculation and distribution logic.
- Scheduled Job:
- Schedule the Batch Apex class to run every 24 hours.
- Testing:
- Thoroughly test the batch job to ensure correct calculation and distribution of interest.
- Custom Field Creation:
- Error Handling:
- Implement error handling and logging to manage any issues that arise during the batch execution, such as data inconsistencies or update failures.
By implementing these requirements, the bank will ensure accurate and timely interest calculations, maintaining financial accuracy and transparency in account balances and opportunity amounts.
# Lets understand the implementation of Batch Class:
global class AccOppBatchClass implements Database.Batchable<sObject>, Schedulable {
global Database.QueryLocator start(Database.BatchableContext BC){
return Database.getQueryLocator([SELECT Id, Name, Account_Amount__c, No_Of_Opp__c FROM Account]);
}
global void execute(Database.BatchableContext BC, List<Account> accList){
Set<id> accId = New Set<Id>();
for(Account a : accList){
if(a.id != Null){
accId.add(a.id);
}
}
Map<Id, Decimal> mapOfAccIdVsAmountTotal = new Map<Id, Decimal>();
Map<Id, Integer> mapOfAccIdVsOppCount = new Map<Id, Integer>();
for(opportunity oppo : [SELECT Id, Amount, AccountId FROM Opportunity WHERE AccountId IN :accId]){
if(mapOfAccIdVsAmountTotal.containskey(oppo.AccountId)){
Decimal tempamount = mapOfAccIdVsAmountTotal.get(oppo.AccountId);
tempAmount = tempAmount + oppo.Amount;
mapOfAccIdVsAmountTotal.put(oppo.AccountId, tempAmount);
//Logic for counting no. of opportunities per account.
Integer count = mapOfAccIdVsOppCount.get(oppo.AccountId);
count = count + 1;
mapOfAccIdVsOppCount.put(oppo.AccountId, count);
}
else{
mapOfAccIdVsAmountTotal.put(oppo.AccountId, oppo.Amount);
mapOfAccIdVsOppCount.put(oppo.AccountId, 1);
}
}
List<Account> aList = New List<Account> ();
for(Id acctid : mapOfAccIdVsAmountTotal.keyset()){
Account acc = New Account();
acc.id = acctid;
acc.Account_Amount__c = mapOfAccIdVsAmountTotal.get(acctid);
acc.Total_Interest__c = 0.01*acc.Account_Amount__c;
acc.No_Of_Opp__c = mapOfAccIdVsOppCount.get(acctid);
acc.Account_Amount__c = acc.Account_Amount__c +(0.01*acc.Account_Amount__c);
aList.add(acc);
}
if(aList != null && aList.size() > 0){
Database.SaveResult[] updateAList = Database.update(aList, false);
// Iterate through each returned result
for (Database.SaveResult sr : updateAList) {
if (sr.isSuccess()) {
// Operation was successful, so get the ID of the record that was processed
System.debug('Successfully updated Record. Record ID: ' + sr.getId());
} else {
// Operation failed, so get all errors
for(Database.Error err : sr.getErrors()) {
System.debug('The following error has occurred.');
System.debug(err.getStatusCode() + ': ' + err.getMessage());
System.debug('Fields that affected this error: ' + err.getFields());
}
}
}
}
//Logic for equally distributing the interest amount.
List<Opportunity> oppListToBeUpdated = new List<Opportunity>();
for(Opportunity opp : [SELECT Id, Amount, Account.No_Of_Opp__c, Account.Total_Interest__c FROM Opportunity WHERE AccountId IN :accId]){
if(opp.Account.Total_Interest__c != NULL && opp.Account.No_Of_Opp__c != NULL){
Decimal amtToBeAdded = (opp.Account.Total_Interest__c / opp.Account.No_Of_Opp__c);
opp.Amount = opp.Amount + amtToBeAdded;
oppListToBeUpdated.add(opp);
}
}
if(oppListToBeUpdated != null && oppListToBeUpdated.size() > 0){
Database.SaveResult[] updateOppList = Database.update(oppListToBeUpdated, false);
// Iterate through each returned result
for (Database.SaveResult sr : updateOppList) {
if (sr.isSuccess()) {
// Operation was successful, so get the ID of the record that was processed
System.debug('Successfully updated Record. Record ID: ' + sr.getId());
} else {
// Operation failed, so get all errors
for(Database.Error err : sr.getErrors()) {
System.debug('The following error has occurred.');
System.debug(err.getStatusCode() + ': ' + err.getMessage());
System.debug('Fields that affected this error: ' + err.getFields());
}
}
}
}
}
global void finish(Database.BatchableContext BC){
}
global void execute(SchedulableContext BC){
AccOppBatchClass accBatch = New AccOppBatchClass();
Database.executeBatch(accBatch);
}
}
Apex