34

I have an "invoice" custom object which has a couple of summarising formula fields in. I also have a complicated and dynamic visualforce page for building the invoice objects.

As the user is completing this form, different areas are dynamically updated to show "latest" values. This is all fine where I am copying data about or performing bespoke lookups and maths, but - in what is really the simplest case - a formula field, I can find no way to get the value to update, without performing some weird cyclic save + reload of the whole object.

This is inappropriate for a couple of reasons (the object should not be saved until the invoice is complete + accepted) and the other option I have found online is to spoof the value by duplicating my formula field maths into the custom controller and re-executing them there - also unacceptable from a code/logic location/duplication perspective.

Is there anyway to "force" an object/page to recalculate it's formula fields, either through standard or extended controllers?

1
  • 1
    this has just been added to Winter16. Please upvote and/or accept the new answer to reflect the change. Commented Oct 22, 2015 at 14:37

5 Answers 5

32

Good news everybody!

This has just been added to the Winter '16 release. It can be used like this:

someSObject.recalculateFormulas();

From the Documentation:

Recalculates all formula fields on an sObject, and sets updated field values. Rather than inserting or updating objects each time you want to test changes to your formula logic, call this method and inspect your new field values. Then make further logic changes as needed.

See https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_sobject.htm

Note that this method doesn’t recalculate cross-object formulas, only 'local' formula's referring to the record itself!

0
8

Unfortunately not. Formula fields aren't stored in a Salesforce record, rather the formula definition is executed at the time that the record is queried from the database. So its the act of retrieval that populates the field based on the formula.

Another option is to save the record, query it from the database including the formula fields, capture the formula fields into controller properties or similar and then delete the record. Its clunky but it will allow you to get at the formula fields without leaving a half-populated record in the database.

2
  • 1
    Another option is to set a savepoint, update/insert the record, then do a rollback. Commented Oct 30, 2012 at 6:13
  • I think this is as close as I'm going to get. I didn't want to have to update the record every time a value was tweeked, because it makes the concept of "cancelling" out of the step redundant, because you arn't cancelling any changes as the user would expect. I have added an upsert to the onchange function and then re-query the formula fields in the component controller. I will have to think of a new way to then allow the user to revert out to the state the object was in before they entered the page. shouldn't be too hard! :) Commented Oct 30, 2012 at 10:28
5

As noted elsewhere, the sObject.recalculateFormulas() does exactly this; unfortunately, however, that feature currently has a bug that makes it much less useful than it could be.

There is a Known Issue regarding this bug, but essentially the problem is that if any non-updatable fields are in the SOQL query that the recalculateFormulas() will be referencing, it will fail. This includes built-in fields (IsDeleted, CreatedDate, etc.) and custom fields, as well as fields referenced from other sObjects in the SOQL query.

1
  • It really is a debilitating bug, unless you want to restructure all your queries to omit a whole bunch of otherwise relevant fields, including any lookup fields. I encourage everyone to upvote the bug report: success.salesforce.com/issues_view?id=a1p300000008bvw
    – smohyee
    Commented Apr 13, 2017 at 19:28
2

In order to "reload" an object and to have the formula fields recalculated without querying it explicitly through SOQL, it is also possible to call the reset() method on the standard controller. Doing so any uncommitted changes on that object will be discarded. So usually the call to reset() should happen after updating the object. See: https://www.salesforce.com/us/developer/docs/pages/Content/apex_ApexPages_StandardController_reset.htm

1

Here is one approach along with a code example that shows a hacky but effective way to evaluate formulas before saving the record, https://jsonhammerle.wordpress.com/2014/07/21/evaluating-a-salesforce-formula-from-a-custom-visualforce-page/

You must log in to answer this question.

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