Requirement : we have 4 critical fields in Opportunity ,whenever these fields are updated with new value, need to capture the reason for updating of that feild, old value , new value & field name with timestamp below are the opportunity feilds with API names
(Expected PO Received Date (CloseDate)
Tracker Delivery: Start Date(Tracker_Delivery_Start_Date__c)
Confidence Level (Confidence_Level__c)
Post Delivery: Start Date (First_Delivery_Date__c))
Solution:
1.made the fields to be read-only in the record page.
2.I have to created a Vf page button on the detail page with this feilds on it like snip i shared, whenever user needs to update these feilds ,he updates in this VF page & saves, then these values should be updated to opportunity Fields + create an opportunity change log related to that record capturing these VFpage changes+ change reasons.
here the issue is even any of Field values are updated & saved the VF page. the valueChanged method is returning false, hence condition is false the logs are not creating, please help
VF page + Extension :
<apex:page showheader="false" standardController="Opportunity" extensions="Opportunityupdateextension">
<apex:form id="form">
<apex:pageBlock title="Capture Field Change Reasons">
<table border="1">
<tr>
<th>Select</th>
<th>Field Label</th>
<th>Field Value</th>
<th>Change Reason</th>
</tr>
<apex:repeat value="{!fields}" var="field" id="repeat">
<tr>
<td>
<apex:inputCheckbox value="{!field.isSelected}" onchange="toggleFields(this)" />
</td>
<td>{!field.fieldLabel}</td>
<td>
<apex:inputField value="{!opp[field.fieldName]}" styleClass="field-value" style="pointer-events: none; background-color: #;" />
</td>
<td>
<apex:inputText value="{!field.changeReason}" styleClass="change-reason" style="pointer-events: none; background-color: #;" required="{!field.isSelected}" />
</td>
</tr>
</apex:repeat>
<tr>
<td colspan="4">
<!-- Call the save method directly -->
<apex:commandButton value="Save" action="{!save}" rerender="form" />
</td>
</tr>
</table>
</apex:pageBlock>
</apex:form>
<script>
function toggleFields(checkbox) {
var row = checkbox.parentNode.parentNode;
var fieldValue = row.getElementsByClassName('field-value')[0];
var changeReason = row.getElementsByClassName('change-reason')[0];
if (checkbox.checked) {
fieldValue.style.pointerEvents = 'auto';
fieldValue.style.backgroundColor = '#ffffff';
changeReason.style.pointerEvents = 'auto';
changeReason.style.backgroundColor = '#ffffff';
changeReason.required = true; // Enable required attribute for change reason
} else {
fieldValue.style.pointerEvents = 'none';
fieldValue.style.backgroundColor = '#f2f2f2';
changeReason.style.pointerEvents = 'none';
changeReason.style.backgroundColor = '#f2f2f2';
changeReason.required = false; // Disable required attribute for change reason
}
}
</script>
</apex:page>
public class Opportunityupdateextension {
// Properties
public List<OpportunityFieldWrapper> fields { get; set; }
public Opportunity opp { get; set; }
// Constructor
public Opportunityupdateextension(ApexPages.StandardController controller) {
// Initialize the fields list
fields = new List<OpportunityFieldWrapper>();
// Query the Opportunity record
opp = [SELECT Id, CloseDate, Tracker_Delivery_Start_Date__c, Confidence_Level__c, First_Delivery_Date__c FROM Opportunity WHERE Id = :controller.getId()];
fields = new List<OpportunityFieldWrapper>();
// Add the Opportunity fields you want to track here
fields.add(new OpportunityFieldWrapper(opp, 'CloseDate', 'Opportunity Expected PO Received Date'));
fields.add(new OpportunityFieldWrapper(opp, 'Tracker_Delivery_Start_Date__c', 'Opportunity Tracker Delivery: Start Date'));
fields.add(new OpportunityFieldWrapper(opp, 'Confidence_Level__c', 'Opportunity Confidence Level'));
fields.add(new OpportunityFieldWrapper(opp, 'First_Delivery_Date__c', 'Opportunity Post Delivery: Start Date'));
// Load the change reasons for each field if they exist
for (OpportunityFieldWrapper field : fields) {
field.loadOriginalValue();
}
}
// In the Opportunityupdateextension class
public PageReference save() {
try {
// Loop through the fields and update their values if they have been changed in the VF page
for (OpportunityFieldWrapper field : fields) {
if (field.isSelected && field.valueChanged()) {
field.updateValue();
field.createChangeLog();
}
}
// Save the Opportunity record
update opp;
return new PageReference('/' + opp.Id); // Redirect to the opportunity record page
} catch (Exception e) {
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Error saving changes: ' + e.getMessage()));
return null;
}
}
// Wrapper class
public class OpportunityFieldWrapper {
// Properties
public String fieldName { get; set; }
public String fieldLabel { get; set; }
public Boolean isSelected { get; set; }
public Object originalValue { get; set; }
public Object newValue { get; set; }
public String changeReason { get; set; }
private Opportunity opportunity;
// Constructor
public OpportunityFieldWrapper(Opportunity opp, String fieldName, String fieldLabel) {
this.opportunity = opp;
this.fieldName = fieldName;
this.fieldLabel = fieldLabel;
this.isSelected = false;
}
// Method to check if the value changed
public Boolean valueChanged() {
return !String.valueOf(originalValue).equals(String.valueOf(newValue));
}
public void updateValue() {
// Convert newValue to the appropriate data type based on fieldName
try {
if (fieldName == 'CloseDate' || fieldName == 'Tracker_Delivery_Start_Date__c' || fieldName == 'First_Delivery_Date__c') {
opportunity.put(fieldName, Date.valueOf(String.valueOf(newValue)));
} else if (fieldName == 'Confidence_Level__c') {
opportunity.put(fieldName, Decimal.valueOf(String.valueOf(newValue)));
} else {
// Handle other data types if needed
opportunity.put(fieldName, newValue);
}
} catch (Exception e) {
System.debug('Error updating field ' + fieldName + ': ' + e.getMessage());
}
}
// Method to create change log
public void createChangeLog() {
Opportunity_Change_Log__c changeLog = new Opportunity_Change_Log__c();
changeLog.Opportunity__c = opportunity.Id;
changeLog.Field_Name__c = fieldLabel;
changeLog.Old_Value__c = String.valueOf(originalValue);
changeLog.New_Value__c = String.valueOf(newValue);
changeLog.Change_Reason__c = changeReason;
insert changeLog;
}
// Method to load original value
public void loadOriginalValue() {
originalValue = opportunity.get(fieldName);
newValue = originalValue;
}
}
}
Appreciate your insights here.
Hi, sorry for the inconvenience. If you don't receive a response here, we recommend reaching out to our support team for further assistance. You can do so by visiting https://help.salesforce.com/s/articleView?id=000393090&language=en_US&type=1