1

Situation: Sales reps use an external quoting tool. It tells them the total amount of all products (product1 and product2) and the separate amount of 1 product (product 2). Rather than them needing to get a calculator out and potentially have errors I'm trying to allow them to put in the total amount in the field for product 1 and the known amount for the field in product 2 and then press a recalculate button that will take what is in the amount for Product 1, subtract Product 2 and either replace the input for product 1 or just show it on the screen.

I am able to do this if the numbers are already saved. So if they save the VF page and then hit recalculate it works fine. However, if they put in a new number for Product 1 on the page it won't take the updated number.

I've tried two things: having the method first do and update to the list being called and then have the recalculation after that AND having the action button directly call the method to save and use oncomplete to call a javascript button to then call the recalulate method. Both continue to use the previously saved amount instead of the new amount. I know the amount is saving because if I go to the Opportunity record and refresh the new amount that I used is there...so the save works, just the calculation continues to use the prior data. How do I get it to use the updated data? Here's what I have and what I've tried. Thanks

VF Page:

 <apex:page standardController="Opportunity" extensions="OLIController" > <apex:form > <apex:pageBlock title="Opportunity Products"> <apex:pageBlockTable var="OLI" value="{!OLIs}" id="newProduct"> <apex:column value="{!OLI.product2ID}"/> <apex:column headerValue="Amount"> <apex:inputfield id="UnitPrice" value="{!OLI.UnitPrice}"/> </apex:column> </apex:pageBlockTable> <apex:outputLabel id="oId">Gross Total: {!grossTotal}</apex:outputLabel> <br/> </apex:pageBlock> <apex:commandButton value="ReCalculate Product Amount" action="{!recalcesave}" oncomplete="recalculate();"/> <br/><br/> <apex:outputLabel id="oIdthree">NewProductAmount: {!NewProductAmount}</apex:outputLabel> <br/> <apex:outputLabel id="oIdfour">ProductAmount: {!productAmount}</apex:outputLabel> <br/> <apex:outputLabel id="oIdfive">PDAmount: {!pdAmount}</apex:outputLabel> <br/> <apex:actionFunction action="{!recalculate}" name="recalculateAF"/> <script> function recalculate() { recalculateAF(); return null; } </script> </apex:form> </apex:page> 

Class Controller:

public with sharing class OLIController { public ApexPages.StandardController sc; public Opportunity Opp {get;set;} public List<OpportunityLineItem> OLIs {get ;set;} public String recordTypeName { get; set; } public String profilename { get; set; } public Integer total {get; set;} public Decimal PDAmount {get; set;} public Decimal ProductAmount {get; set;} public Decimal NewProductAmount {get; set;} public OLIController(ApexPages.StandardController sc) { this.Opp = (Opportunity)sc.getRecord(); OLIs = [Select Name, TotalPrice, ID, Product2ID, UnitPrice, Product2.Name, OpportunityId FROM OpportunityLineItem WHERE OpportunityId =:Opp.Id]; recordTypeName = [Select Name from RecordType where Id=:this.Opp.recordTypeId][0].name; Id profileId=userinfo.getProfileId(); profileName=[Select Id,Name from Profile where Id=:profileId].Name; } public List<OpportunityLineItem> getOLIs() { List<OpportunityLineItem> OLIs = [Select Name, TotalPrice, Product2ID, ID, UnitPrice, OpportunityId FROM OpportunityLineItem WHERE OpportunityId =:Opp.Id]; return OLIs; } // controller method to get gross total of products public Decimal getGrossTotal(){ Decimal grossTotal = 0; for(OpportunityLineItem pw : OLIs) { grossTotal += (pw.unitPrice * pw.quantity); } return grossTotal; } // controller method to recalculate product total public PageReference recalculate(){ for(OpportunityLineItem pw : OLIs) { if(pw.Name.Contains('PD')) { pdAmount = pw.TOTALPRICE; } else { productAmount = pw.TOTALPRICE; } } if(PDAmount!=0){ NewProductAmount = ProductAmount-PDAmount; } return null; } //Save before recalculate public PageReference recalcesave() { update OLIs; return null; } } 

The other version I have tried of recalcsave is:

public PageReference recalcsave(){ update OLIs; for(OpportunityLineItem pw : OLIs) { if(pw.Name.Contains('PD')) { pdAmount = pw.TOTALPRICE; } else { productAmount = pw.TOTALPRICE; } } if(PDAmount!=0){ NewProductAmount = ProductAmount-PDAmount; } return null; } 
2
  • usually this is solved with apex:action regions and rerender=; see Using Ajax in a page Commented Oct 4, 2023 at 17:12
  • @cropredy The region isn't necessary, but the rerender is. Commented Oct 5, 2023 at 0:02

1 Answer 1

1

When you use a command button or command link, the oncomplete will be called if, and only if, you invoke the action as an AJAX call. To do this, you must specify a rerender attribute, although you need not provide an actual target. For example:

<apex:commandButton rerender="" value="ReCalculate Product Amount" action="{!recalcesave}" oncomplete="recalculate();"/> 

Similarly, note that not having a rerender target on an action function will refresh the entire page. I'd advise just refreshing the form, as in:

<apex:form id="form"> ... <apex:actionFunction action="{!recalculate}" name="recalculateAF" rerender="form" /> 

As this will provide a (relatively) better user experience.

Finally, not related to the main problem, I typically recommend that developers do not declare that they are returning a PageReference when they are not actually doing so. This can mislead other developers into thinking there may be a possible page redirect in the code. For a short method, this may be fine, but for longer methods, this is just extra cognitive load that doesn't need to be there.

public void recalculate(){ for(OpportunityLineItem pw : OLIs) { if(pw.Name.Contains('PD')) { pdAmount = pw.TOTALPRICE; } else { productAmount = pw.TOTALPRICE; } } if(PDAmount!=0){ NewProductAmount = ProductAmount-PDAmount; } } 
1
  • Thank you so much! I had tried rerender before and it hadn't helped but I only had it in either the command button or the action function but not both so maybe that is why it didn't work? It also didn't seem to work at first with rerender on both because unbeknownst to me it was having a background error regarding updating unitprice and totalprice at the same time (my update OLIs) but once I removed TotalPrice from the class it worked perfectly. Thank you so much. Commented Oct 5, 2023 at 16:31

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.