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
shail.sfdcshail.sfdc 

Formula Field : Order of execution

I've to write a Simple validation in my Custom VF/Apex code where a formula field (Grand Total which depends on 3 other fields) should not exceed a set number. If it does I would write a condition in my Apex code & add a error message to page. 

My Issue is that I think formula fields are only evaluated once the record is saved & when the page loads again & that's the reason I can't check for the modified Grand Total field in my apex code when User saves a record. 

 

Any workaround this , can this be achieved through After Trigger ?

Best Answer chosen by Admin (Salesforce Developers) 
shail.sfdcshail.sfdc

Thanks for the quick response Bob. 

 

I tried validation in a before Trigger & to my surprise( I thought Formula values are only calculated after data is committed) the new calculated formula value was available in the triggr. I wrote a simple Before trigger which is servicng my purpose correctly as below(As far as I've test it). But I think there has to be a catch, do you see any issue with below code. 

 

trigger Trigger_ValidateGrandTotal on Account (before update) {

for( Account acc:trigger.new)
{
if(acc.Grand_Total__c > 50)
{
acc.addError('Limit Exceeded');
break;
}
}
}

All Answers

Saravanan @CreationSaravanan @Creation

Hi,

 

The formula field is calculated after the record save.So you can't you formula field

 

In the trigger calculate the calculate the value and validate it.

 

 

bob_buzzardbob_buzzard
The formula field will be populated in the after trigger records, as it is generated on demand when you query from the database.

The after trigger is the right place to be using it IMHO, but you'll need to execute some SOQL that pulls copies of all of the trigger records from the database including the formula field.
bob_buzzardbob_buzzard

I wouldn't recommend replicating the formula in the trigger - that way if you need to change the formula at any point in the future, you have to change two copies, which goes against DRY.

kriskkrisk

Here is a trigger that does something similar to what you are looking for 

 

There is a Project object that has two fields a) Budget amount and b) Total Payments amount and there is another object called Payment object that when you create or edit rolls up the Amount into Total Payments field. When adding the Amounts the system has to ensure that the Total Payments Amount does not exceed Budget amount 

 

 

trigger projectPayments on Payment__c (before insert, before update) {
List<Payment__c> payments = new List<Payment__c>();
List<Project__c> projects = new List<Project__c>();
Decimal totalAmount = 0;
Decimal actualAmount = 0;
if(Trigger.isInsert) {
for (Payment__c payment: Trigger.new ) {

Project__c project = [Select p.Id, p.Total_Payments__c, p.Budget__c from Project__c p where p.Id = :payment.Project__c];

if(project != null && project.Total_Payments__c != null) {

project.Total_Payments__c = project.Total_Payments__c + payment.Amount__c;

if(project.Total_Payments__c > project.Budget__c){
payment.addError('actual exceeds budget');
}

} else {
project.Total_Payments__c = payment.Amount__c;
}
projects.add(project);
} 
} else if(Trigger.isUpdate){

system.debug('update');
for (Payment__c payment: Trigger.new ) {

Payment__c oldPaymentObject = Trigger.oldMap.get(payment.Id);
Project__c project = [Select p.Id, p.Total_Payments__c, p.Budget__c from Project__c p where p.Id = :payment.Project__c];

Decimal oldAmount = oldPaymentObject.Amount__c;
Decimal newAmount = payment.Amount__c;
Decimal diff = 0;
if(oldAmount != newAmount){
diff = newAmount - oldAmount;
system.debug(diff);
}

if(project != null && project.Total_Payments__c != null) {
project.Total_Payments__c = project.Total_Payments__c + diff;
} else {
project.Total_Payments__c = diff;
}
if(project.Total_Payments__c > project.Budget__c){
system.debug('total exceeds budget');
payment.addError('actual exceeds budget');
}

projects.add(project);
}
}
update projects;
}

 

bob_buzzardbob_buzzard

In this trigger you have a SOQL query embedded inside a for loop:

 

for (Payment__c payment: Trigger.new ) {

Project__c project = [Select p.Id, p.Total_Payments__c, p.Budget__c from Project__c p where p.Id = :payment.Project__c];

 This means that as soon as your trigger processes more than 100 records it is guaranteed to break the SOQL query governor limit I'm afraid.

ItswasItswas

Hi shail,

 

we cannot go for any work arounf,bcoz we all know that flow excution is from before trigger,validation and after trigger ,then workflow.So I will suggest you to remove the formula fileds from custom object and create a simple number/text field and go for 

calculation(as per your requirment it will calculate and find the grandtotal) thrugh apex and check it before inserting to the object .

 

Regards,

Itswas.

shail.sfdcshail.sfdc

Thanks for the quick response Bob. 

 

I tried validation in a before Trigger & to my surprise( I thought Formula values are only calculated after data is committed) the new calculated formula value was available in the triggr. I wrote a simple Before trigger which is servicng my purpose correctly as below(As far as I've test it). But I think there has to be a catch, do you see any issue with below code. 

 

trigger Trigger_ValidateGrandTotal on Account (before update) {

for( Account acc:trigger.new)
{
if(acc.Grand_Total__c > 50)
{
acc.addError('Limit Exceeded');
break;
}
}
}

This was selected as the best answer
bob_buzzardbob_buzzard
If that is giving you the correct value, then happy days! I'm slightly surprised as I wouldn't expect the latest values to be used in the formula calculation until the after trigger, but its not something I've used that recently so I'm not shocked.
shail.sfdcshail.sfdc

Thanks for your Input friends, I was able to make i work using the trigger I posted before. 

Appreciate your help

a.ka.k
Values are availabe in before insert. Don't know whether i should rely on formuala field in before insert or not.