0

When multi-currencies support is activated the amount field on the opportunity cannot be rolled-up. To work around this I created an Apex class with a method that will read Amount, CloseDate, and CurrencyISOCode from an Opportunity, and calculate the converted amount.

I then use this in a workflow that triggers on Amount or CurrencyISOCode change, runs the Apex class to calculate the converted amount, and sets the Converted_Amount__c field (a custom Number field that I created on the Opportunity object.

The workflow runs fine in debug mode and the calculation is performed right, but when I run it live it does not work.

Here is some additional background on this:

Objective Have a roll-up field on Account showing sum of all converted amounts of open opportunities. Challenge The Converted Amount is not part of the model, it’s calculated in reports. When multiple currencies support is activated, the Amount field is not available as a roll-up field. Attempted solution Create a custom Converted_Amount__c Decimal field on the Opportunity, and create a workflow that will trigger on either Amount or CurrencyISOCode change. When triggered it will run an APEX Action to return the converted amount, and then run an Assignment action to update the opportunity Converted_Amount__c field.

Problem

The flow works in Debug mode, but when performing a change on Amount or CurrencyISOCode the Converted_Amount__c field is not updated. Logs show that the flow and the apex class are both triggered. The converted amount is calculated properly, but for whatever reason the Converted_Amount__c field is not updated.

Setup

Workflow

Set Converted Amount on Price Change Workflow

Start Action / Trigger

Start Action

Apex Action Step

Apex Action Step

Assignment Step

Assignment Step

Debug of the flow (Update + changing amount)

Debugging of the flow

Debug results / Working fine ends up assigning to records Converted_Amount__c

Debug Results OK

Apex Class

public class ConvertedOpportunityAmountCalculation {
    @InvocableMethod(label='Calculate Converted Amount' description='Returns the converted currency amount for given opportunity' category='Opportunity')
    public static List<ConvertedAmountResponse> convertedOpportunityAmount(List<OpportunityRequest> requests) {
        List<ConvertedAmountResponse> returnConvertedAmountList = new List<ConvertedAmountResponse>();
        
        for (OpportunityRequest request : requests) {
            Opportunity opp = request.opportunity;
            DatedConversionRate conversionRateRecord = [
                SELECT ConversionRate
                FROM DatedConversionRate
                WHERE IsoCode = :opp.CurrencyIsoCode
                    AND StartDate <= :opp.CloseDate
                    AND NextStartDate > :opp.CloseDate
                LIMIT 1
            ];
            ConvertedAmountResponse resp = new ConvertedAmountResponse();
            resp.ConvertedAmount = (opp.Amount * conversionRateRecord.ConversionRate).setScale(2);
            returnConvertedAmountList.add(resp);
        }
        return returnConvertedAmountList;
    }
    
    public class OpportunityRequest{
        @InvocableVariable(label='Opportunity' description='Opportunity')
        public Opportunity opportunity;
    }
    
    public class ConvertedAmountResponse{
        @InvocableVariable(label='ConvertedAmount' description='ConvertedAmount')
        public Decimal ConvertedAmount;
    }

}

Trying the workflow with a change on an opportunity

Change on an opportunity

The “Converted Amount” field remains blank !!! (Not Expected knowing Workflow works in Debug!)

Field Converted Amount remains blank

Logs

The log shows that the Workflow is triggered, that the amount is calculated correctly 58.0

APEX_CODE,FINEST;APEX_PROFILING,INFO;CALLOUT,INFO;DB,INFO;NBA,INFO;SYSTEM,DEBUG;VALIDATION,INFO;VISUALFORCE,INFO;WAVE,INFO;WORKFLOW,INFO
10:31:56.0 (200294)|USER_INFO|[EXTERNAL]|0057Q000002m87L|[email protected]|(GMT+02:00) Central European Summer Time (Europe/Berlin)|GMT+02:00
10:31:56.0 (260453)|EXECUTION_STARTED
10:31:56.0 (267255)|CODE_UNIT_STARTED|[EXTERNAL]|Flow:Opportunity
10:31:56.3 (3469875)|FLOW_CREATE_INTERVIEW_BEGIN|00D5E000000BZRz|3007Q000000ddr8|3017Q000000j2wb
10:31:56.3 (3675020)|FLOW_CREATE_INTERVIEW_END|99fc2799ef5d66227927c5278718a1c59e6e6-3324|Opportunities_by_child
10:31:56.3 (3998544)|FLOW_START_INTERVIEWS_BEGIN|1
10:31:56.3 (4055730)|FLOW_START_INTERVIEW_BEGIN|99fc2799ef5d66227927c5278718a1c59e6e6-3324|Opportunities_by_child
10:31:56.3 (5655240)|FLOW_START_INTERVIEW_END|99fc2799ef5d66227927c5278718a1c59e6e6-3324|Opportunities_by_child
10:31:56.3 (12272394)|FLOW_START_INTERVIEWS_END|1
10:31:56.3 (12329145)|FLOW_INTERVIEW_FINISHED|99fc2799ef5d66227927c5278718a1c59e6e6-3324|Opportunities_by_child
10:31:56.14 (14890480)|FLOW_CREATE_INTERVIEW_BEGIN|00D5E000000BZRz|3005E000000R1SG|3015E000001ArSg
10:31:56.14 (14940244)|FLOW_CREATE_INTERVIEW_END|100fc2799ef5d66227927c5278718a1c59e6e6-3323|Set Converted Amount on Price Change
10:31:56.15 (15197381)|FLOW_START_INTERVIEWS_BEGIN|1
10:31:56.15 (15241519)|FLOW_START_INTERVIEW_BEGIN|100fc2799ef5d66227927c5278718a1c59e6e6-3323|Set Converted Amount on Price Change
10:31:56.15 (16310783)|FLOW_START_INTERVIEW_END|100fc2799ef5d66227927c5278718a1c59e6e6-3323|Set Converted Amount on Price Change
10:31:56.21 (21192568)|PUSH_TRACE_FLAGS|[EXTERNAL]|01p5E000009tvqV|ConvertedOpportunityAmountCalculation|APEX_CODE,FINEST;APEX_PROFILING,INFO;CALLOUT,INFO;DB,INFO;NBA,INFO;SYSTEM,DEBUG;VALIDATION,INFO;VISUALFORCE,INFO;WAVE,INFO;WORKFLOW,INFO
10:31:56.21 (21299311)|CODE_UNIT_STARTED|[EXTERNAL]|01p5E000009tvqV|ConvertedOpportunityAmountCalculation.convertedOpportunityAmount(List<ConvertedOpportunityAmountCalculation.OpportunityRequest>)
10:31:56.21 (21516881)|HEAP_ALLOCATE|[79]|Bytes:3
10:31:56.21 (21560605)|HEAP_ALLOCATE|[84]|Bytes:152
10:31:56.21 (21578404)|HEAP_ALLOCATE|[399]|Bytes:408
10:31:56.21 (21603548)|HEAP_ALLOCATE|[412]|Bytes:408
10:31:56.21 (21619832)|HEAP_ALLOCATE|[520]|Bytes:48
10:31:56.21 (21642294)|HEAP_ALLOCATE|[139]|Bytes:6
10:31:56.21 (21752355)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:8
10:31:56.21 (21769218)|VARIABLE_SCOPE_BEGIN|[23]|this|ConvertedOpportunityAmountCalculation.OpportunityRequest|true|false
10:31:56.21 (21867934)|VARIABLE_ASSIGNMENT|[23]|this|{}|0x108b66e8
10:31:56.21 (21889405)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:6
10:31:56.21 (21951913)|STATEMENT_EXECUTE|[23]
10:31:56.21 (21955193)|STATEMENT_EXECUTE|[25]
10:31:56.21 (22074453)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:4
10:31:56.21 (22086337)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:8
10:31:56.21 (23218257)|VARIABLE_ASSIGNMENT|[EXTERNAL]|this.opportunity|{"LastModifiedDate":"2023-08-22T08:31:56.000Z","AccountId":"0015E00003OLi9HQAT","HasOpportunityLineItem":false,"Price__c":1.9,"ShipDate__c":"2023-12-21T00:00:00.000Z","ForecastCategory":"Pipeline","IsClosed":false,"CloseDate":"2023-11-25T00:00:00.000Z","Name":"Skin Care","HasOpenActivity":false,"Turnkey__c":false,"TotalOpportunityQuantity":7000.0,"LastAmountChangedHistoryId":"0085E00002hIf9aQAC","ExpectedRevenue":2500.0,"OwnerId":"0057Q000002m87LQAQ","CreatedById":"0057Q000002m87LQAQ","Demo__c":false,"IsWon":false,"RecordTypeId":"0127Q0000006DpBQAU","ROIAnalysisCompleted__c":false,"ZTECH_MFG_SWIZTERLAND__c":false,"IsDeleted":false,"ZTECH_MFG_ITALY__c":false,"StageName":"Submission Made","Amount":12500.0,"Probability":20.0,"CurrencyIsoCode":"USD","SystemModstamp":"2023-08-22T08:31:56.000Z","BudgetConfirmed__c":false,"DiscoveryCompleted__c":false,"TASKRAY__trOnboardingKickoffCompleted__c":false,"CreatedDate":"2023-08-21T14:42:44.000Z","HasOverdueTask":false,"Id":"0065E00002RPYHkQAP","ForecastCategoryName":"Pipeline","IsPrivate":false,"LastModifiedById":"0057Q000002m87LQAQ"}|0x108b66e8
10:31:56.21 (23271733)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:8
10:31:56.21 (23388675)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:42
10:31:56.21 (23398861)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:1
10:31:56.21 (23435289)|METHOD_ENTRY|[1]|01p5E000009tvqV|ConvertedOpportunityAmountCalculation.ConvertedOpportunityAmountCalculation()
10:31:56.21 (23446638)|STATEMENT_EXECUTE|[1]
10:31:56.21 (23454112)|STATEMENT_EXECUTE|[1]
10:31:56.21 (23458146)|STATEMENT_EXECUTE|[23]
10:31:56.21 (23462194)|STATEMENT_EXECUTE|[28]
10:31:56.21 (23474285)|METHOD_EXIT|[1]|ConvertedOpportunityAmountCalculation
10:31:56.21 (23566621)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:8
10:31:56.21 (23588143)|VARIABLE_SCOPE_BEGIN|[3]|requests|List<ConvertedOpportunityAmountCalculation.OpportunityRequest>|true|false
10:31:56.21 (23662485)|VARIABLE_ASSIGNMENT|[3]|requests|[{"opportunity":"0x8aef431"}]|0x9763766
10:31:56.21 (23687034)|STATEMENT_EXECUTE|[3]
10:31:56.21 (23690720)|STATEMENT_EXECUTE|[4]
10:31:56.21 (23780179)|HEAP_ALLOCATE|[4]|Bytes:4
10:31:56.21 (23888230)|VARIABLE_SCOPE_BEGIN|[4]|returnConvertedAmountList|List<ConvertedOpportunityAmountCalculation.ConvertedAmountResponse>|true|false
10:31:56.21 (23916251)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:4
10:31:56.21 (23934281)|VARIABLE_ASSIGNMENT|[4]|returnConvertedAmountList|[]|0x44189c4a
10:31:56.21 (24131718)|HEAP_ALLOCATE|[52]|Bytes:5
10:31:56.21 (24163286)|HEAP_ALLOCATE|[58]|Bytes:5
10:31:56.21 (24175195)|HEAP_ALLOCATE|[66]|Bytes:7
10:31:56.21 (24192558)|HEAP_ALLOCATE|[6]|Bytes:5
10:31:56.21 (24212737)|HEAP_ALLOCATE|[6]|Bytes:8
10:31:56.21 (24225122)|VARIABLE_SCOPE_BEGIN|[6]|request|ConvertedOpportunityAmountCalculation.OpportunityRequest|true|false
10:31:56.21 (24266156)|VARIABLE_ASSIGNMENT|[6]|request|{"opportunity":"0x8aef431"}|0x108b66e8
10:31:56.21 (24274589)|STATEMENT_EXECUTE|[6]
10:31:56.21 (24277506)|STATEMENT_EXECUTE|[7]
10:31:56.21 (24285336)|VARIABLE_SCOPE_BEGIN|[7]|opp|Opportunity|true|false
10:31:56.21 (25225551)|VARIABLE_ASSIGNMENT|[7]|opp|{"LastModifiedDate":"2023-08-22T08:31:56.000Z","AccountId":"0015E00003OLi9HQAT","HasOpportunityLineItem":false,"Price__c":1.9,"ShipDate__c":"2023-12-21T00:00:00.000Z","ForecastCategory":"Pipeline","IsClosed":false,"CloseDate":"2023-11-25T00:00:00.000Z","Name":"Skin Care","HasOpenActivity":false,"Turnkey__c":false,"TotalOpportunityQuantity":7000.0,"LastAmountChangedHistoryId":"0085E00002hIf9aQAC","ExpectedRevenue":2500.0,"OwnerId":"0057Q000002m87LQAQ","CreatedById":"0057Q000002m87LQAQ","Demo__c":false,"IsWon":false,"RecordTypeId":"0127Q0000006DpBQAU","ROIAnalysisCompleted__c":false,"ZTECH_MFG_SWIZTERLAND__c":false,"IsDeleted":false,"ZTECH_MFG_ITALY__c":false,"StageName":"Submission Made","Amount":12500.0,"Probability":20.0,"CurrencyIsoCode":"USD","SystemModstamp":"2023-08-22T08:31:56.000Z","BudgetConfirmed__c":false,"DiscoveryCompleted__c":false,"TASKRAY__trOnboardingKickoffCompleted__c":false,"CreatedDate":"2023-08-21T14:42:44.000Z","HasOverdueTask":false,"Id":"0065E00002RPYHkQAP","ForecastCategoryName":"Pipeline","IsPrivate":false,"LastModifiedById":"0057Q000002m87LQAQ"}|0x8aef431
10:31:56.21 (25253953)|STATEMENT_EXECUTE|[8]
10:31:56.21 (25265726)|HEAP_ALLOCATE|[8]|Bytes:136
10:31:56.21 (25290577)|HEAP_ALLOCATE|[8]|Bytes:4
10:31:56.21 (25307416)|HEAP_ALLOCATE|[8]|Bytes:7
10:31:56.21 (25348594)|HEAP_ALLOCATE|[8]|Bytes:7
10:31:56.21 (25382440)|HEAP_ALLOCATE|[8]|Bytes:7
10:31:56.21 (25931657)|SOQL_EXECUTE_BEGIN|[8]|Aggregations:0|SELECT ConversionRate FROM DatedConversionRate WHERE (IsoCode = :tmpVar1 AND StartDate <= :tmpVar2 AND NextStartDate > :tmpVar3) LIMIT 1
10:31:56.21 (32020809)|SOQL_EXECUTE_END|[8]|Rows:1
10:31:56.21 (32063610)|HEAP_ALLOCATE|[8]|Bytes:8
10:31:56.21 (32094922)|HEAP_ALLOCATE|[8]|Bytes:83
10:31:56.21 (32164723)|HEAP_ALLOCATE|[8]|Bytes:8
10:31:56.21 (32183679)|HEAP_ALLOCATE|[8]|Bytes:45
10:31:56.21 (32257048)|HEAP_ALLOCATE|[8]|Bytes:12
10:31:56.21 (32271094)|VARIABLE_SCOPE_BEGIN|[8]|conversionRateRecord|DatedConversionRate|true|false
10:31:56.21 (32315600)|VARIABLE_ASSIGNMENT|[8]|conversionRateRecord|{"ConversionRate":0.900000,"Id":"04w7Q000000PEE4QAO"}|0x8b04415
10:31:56.21 (32323696)|STATEMENT_EXECUTE|[16]
10:31:56.21 (32336736)|HEAP_ALLOCATE|[16]|Bytes:8
10:31:56.21 (32357233)|CONSTRUCTOR_ENTRY|[16]|01p5E000009tvqV|<init>()|ConvertedOpportunityAmountCalculation.ConvertedAmountResponse
10:31:56.21 (32390292)|VARIABLE_SCOPE_BEGIN|[28]|this|ConvertedOpportunityAmountCalculation.ConvertedAmountResponse|true|false
10:31:56.21 (32435087)|VARIABLE_ASSIGNMENT|[28]|this|{}|0x3310df02
10:31:56.21 (32462499)|STATEMENT_EXECUTE|[28]
10:31:56.21 (32466378)|STATEMENT_EXECUTE|[30]
10:31:56.21 (32471861)|CONSTRUCTOR_EXIT|[16]|01p5E000009tvqV|<init>()|ConvertedOpportunityAmountCalculation.ConvertedAmountResponse
10:31:56.21 (32479942)|VARIABLE_SCOPE_BEGIN|[16]|resp|ConvertedOpportunityAmountCalculation.ConvertedAmountResponse|true|false
10:31:56.21 (32498470)|VARIABLE_ASSIGNMENT|[16]|resp|{}|0x3310df02
10:31:56.21 (32504841)|STATEMENT_EXECUTE|[17]
10:31:56.21 (33284052)|HEAP_ALLOCATE|[17]|Bytes:28
10:31:56.21 (33297903)|HEAP_ALLOCATE|[17]|Bytes:28
10:31:56.21 (33456423)|HEAP_ALLOCATE|[17]|Bytes:28
10:31:56.21 (33462917)|HEAP_ALLOCATE|[17]|Bytes:28
10:31:56.21 (33499199)|VARIABLE_ASSIGNMENT|[17]|this.ConvertedAmount|11250.00|0x3310df02
10:31:56.21 (33507133)|STATEMENT_EXECUTE|[18]
10:31:56.21 (33555053)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:4
10:31:56.21 (33581970)|HEAP_ALLOCATE|[6]|Bytes:5
10:31:56.21 (33602239)|VARIABLE_ASSIGNMENT|[6]|request|null|
10:31:56.21 (33608954)|STATEMENT_EXECUTE|[20]
10:31:56.33 (33696830)|CUMULATIVE_LIMIT_USAGE
10:31:56.33 (33696830)|LIMIT_USAGE_FOR_NS|(default)|
  Number of SOQL queries: 1 out of 100
  Number of query rows: 1 out of 50000
  Number of SOSL queries: 0 out of 20
  Number of DML statements: 0 out of 150
  Number of Publish Immediate DML: 0 out of 150
  Number of DML rows: 0 out of 10000
  Maximum CPU time: 8 out of 10000
  Maximum heap size: 0 out of 6000000
  Number of callouts: 0 out of 100
  Number of Email Invocations: 0 out of 10
  Number of future calls: 0 out of 50
  Number of queueable jobs added to the queue: 0 out of 50
  Number of Mobile Apex push calls: 0 out of 10

10:31:56.33 (33696830)|CUMULATIVE_LIMIT_USAGE_END

10:31:56.21 (33768566)|CODE_UNIT_FINISHED|ConvertedOpportunityAmountCalculation.convertedOpportunityAmount(List<ConvertedOpportunityAmountCalculation.OpportunityRequest>)
10:31:56.21 (33818743)|POP_TRACE_FLAGS|[EXTERNAL]|01p5E000009tvqV|ConvertedOpportunityAmountCalculation|APEX_CODE,FINEST;APEX_PROFILING,INFO;CALLOUT,INFO;DB,INFO;NBA,INFO;SYSTEM,DEBUG;VALIDATION,INFO;VISUALFORCE,INFO;WAVE,INFO;WORKFLOW,INFO
10:31:56.15 (39111400)|FLOW_START_INTERVIEWS_END|1
10:31:56.15 (39138817)|FLOW_INTERVIEW_FINISHED|100fc2799ef5d66227927c5278718a1c59e6e6-3323|Set Converted Amount on Price Change
10:31:56.0 (40359267)|CODE_UNIT_FINISHED|Flow:Opportunity
10:31:56.0 (40377378)|EXECUTION_FINISHED

The log shows that the Apex class is triggering when Amount or Currency field is updated, but despite this the Converted_Amount__c field is not updated.

I'm probably missing something obvious, but would appreciate any help, thanks !

2
  • 1
    Have you checked the Converted_Amount__c FLS? - help.salesforce.com/s/… Aug 22, 2023 at 11:16
  • 1
    you may have automation downstream of the Flow that reverts the value
    – cropredy
    Aug 22, 2023 at 18:56

2 Answers 2

0

Thanks for the comments, in the end the solution was simple and was provided to me by Salesforce support.

The "Assignment" component only works for "Fast Field Update" flows. But Fast Update does not work with Apex call so I was forced into "Action and Related Records".

I replaced the "Assignment" component with an "Update Records" component and it worked fine.

Replacement of Assignment with Update Records

This being said, in the meantime I found a much simpler way of achieving the same purpose, the use of an Apex Trigger that directly updates the Converted_Amount__c field. No need for a flow and the Apex code is way simpler as it does not require all the "invocable" stuff. I share it below for those who may have the same requirement.

trigger OpportunityTrigger on Opportunity (before insert, before update) {
    for(Opportunity opp : Trigger.new) {
        DatedConversionRate conversionRateRecord = [
                SELECT ConversionRate
                FROM DatedConversionRate
                WHERE IsoCode = :opp.CurrencyIsoCode
                    AND StartDate <= :opp.CloseDate
                    AND NextStartDate > :opp.CloseDate
                LIMIT 1
        ];
        opp.Converted_Amount__c = (opp.Amount / conversionRateRecord.ConversionRate).setScale(2);
    }   
}

With this I managed to create a roll-up field on the account that will sum the converted amount of open opportunities.

All that's needed is mass updating the Converted_Amount__c fields through DataLoader so I start with a fully calculated field, as the trigger will only act on change.

0

In this next article you can find a solution using an Appexchange application which involves none development.

This application basically maintains the exchange rate on the opportunity using the closeDate field, and only by adding a formula field: Amount/DatedExchangeRate you can have the Corporate Converted Amount. Then adding the Rollup Summary summing Corporate Converted Amount will work.

You must log in to answer this question.

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