3

Requirement: When an opportunity's stage is one of several values, allow Opportunity Products to be edited as normal. Otherwise, disallow the edit and display a message with some key fields from the OppProduct record. The primary use case is the Edit action from the Related List on the Opportunity, as we have removed the Edit button from the Opportunity Product page layout.

In classic, we can do the following:

  1. Create a VF Page with the OpportunityProduct standard controller, which displays the message and key fields.
  2. Add an action param to the apex:page tag to check the criteria and redirect if an edit is allowed.

Here's my first attempt. Note that in my case, I need to allow edits only if the Opportunity Stage Name starts with "11%", "21%", "31%", or "41%", so I'm using a simple string check.

<apex:page standardController="OpportunityLineItem"
           action="{!IF(CONTAINS('11%21%31%41%',LEFT(OpportunityLineItem.Opportunity.StageName,3)),
                      URLFOR($Action.OpportunityLineItem.Edit, OpportunityLineItem.Id, null, true),
                      null)}">
    <div style="display:none">{!OpportunityLineItem.Opportunity.StageName}</div>
    <div>No edits are allowed on the Opportunity Product. Any changes must be made through the related Primary Quote.</div
    <apex:pageBlock>
        <apex:pageBlockSection title="Opportunity Product Information">
             <apex:outputField value="{!OpportunityLineItem.Name}"/>
             <!-- etc. -->
        </apex:pageBlockSection>
    </apex:pageBlock
</apex:page>

Note that I had to output {!OpportunityLineItem.Opportunity.StageName} in the page body in order to use it in the action formula.

When used in Classic, this page correctly redirects to the standard edit page when the Stage matches the correct pattern, or remains and shows the outputFields if not.

When used in LEX, this page also correctly redirects the VF page and chooses the right behavior, however, when an edit is allowed, the redirect to the Edit view appears as the standard "Edit" popover window with a blank LEX tab behind it, instead of the prior page behind it as you would see without an action override.

LEX Edit View

In both Classic and LEX, however, if you end up in the Edit view, there is an issue - both Save and Cancel buttons redirect you back to the same Edit view. After some research and testing, I found the workaround is to pass saveURL and retURL params to URLFOR, so that the action property of the VF page becomes:

action="{!IF(CONTAINS('11%21%31%41%',LEFT(OpportunityLineItem.Opportunity.StageName,3)),
  URLFOR($Action.OpportunityLineItem.Edit, 
         OpportunityLineItem.Id, 
         [saveURL=URLFOR($Action.OpportunityLineItem.View, OpportunityLineItem.Id),
           retURL=URLFOR($Action.OpportunityLineItem.View, OpportunityLineItem.Id)], 
         true),
  null)}"

Note here that I'm redirecting to the OpportunityProduct View and not the Opportunity View in order to simplify things; if I can get everything working correctly I may switch these back to the Opportunity View.

With this change, when viewing in Classic, the redirect works as before, and clicking either Save or Cancel works correctly.

However, when viewing in LEX, the addition of retURL and saveURL causes the Classic Edit view to be presented in a LEX tab instead of the LEX popup edit view, AND Cancel and Save remains broken; you are left on a blank LEX tab with the URL lightning/r/OpportunityLineItem/00k4u000010ryoNAAQ/edit?navigationLocation=RELATED_LIST_ROW&inContextOfRef=(a long string of charaters) with nothing displayed.

Since I cannot get the VF page to work correctly in LEX, I decided to try a Lightning Component override. As of this writing, that means using Aura.

<aura:component implements="lightning:actionOverride,force:hasRecordId">
  <aura:attribute name="oppProduct" type="Object"/>
  <aura:attribute name="cannotEdit" type="Boolean" default="false"/>
  <lightning:navigation aura:id="navService"/>
  <force:recordData fields="Name,OpportunityId,Opportunity.StageName"
                    recordId="{!v.recordId}"
                    targetFields="{!v.oppProduct}"
                    recordUpdated="{!c.handleRecordData}">
  </force:recordData>
  <!-- omitted non-edit view -->
</aura:component>

controller:

({
    handleRecordData: function(cmp, event, helper) {
        var stage = cmp.get("v.oppProduct.Opportunity.StageName");
        console.log("stage: ", stage);
        if ( /^[1234]1%/.test(stage) ) {
            var navService = cmp.find("navService");
            var pageRef = {
                type: "standard__recordPage",
                attributes: {
                    objectApiName: "OpportunityLineItem",
                    recordId: cmp.get("v.recordId"),
                    actionName: "edit"
                },
                state: {
                    nooverride: 1
                }
            }
            navService.navigate(pageRef);
        }
        else {
            cmp.set("v.cannotEdit", true);
        }
    }
});

Again, the basic logic to redirect or not works fine, but when the Edit view is displayed, it's like the original VF version - the Edit Popup View occurs against a blank LEX page. Clicking Cancel leaves you on the same blank page, and clicking Save shows a success toast, and then re-displays the popup Edit view.

What is the correct way to implement a conditional Action override in LEX?

1 Answer 1

0

Okay, posting this as a maybe-answer because the site ate my comment.

Have you tried using validation rules for this? I looked through your question to see if you considered it, and came up empty, so possibly not. Specifically, regarding this requirement:

"Otherwise, disallow the edit and display a message with some key fields from the OppProduct record."

How hard a requirement is the italicized portion? Other than that, validation rules seem like they're practically tailor-made for this situation.

That said, I'm not entirely sure why you have this as a requirement at all; ideally, from an end-user perspective, you'd have the primary quote sync both ways: adding a line item to the opportunity would add it to the primary quote, and vice versa. Any reasons to lock down line items on one would apply just as well to the other.

Unless your issue is that some users aren't supposed to be able to see quotes at all, in which case the answer is probably validation rules again, but including the user's profile as part of the validation formula. Something like:

$User.ProfileId = "(Insert Banned ID Here)" && 
(ISPICKVAL(StageName, "(Insert Banned Stage Here)")) ||
ISBLANK(Example_Other_Field__c))
2
  • A validation rule prevents saving of edits; I need to prevent the user from reaching the edit screen. Otherwise, it's going to be a poor user experience: Click edit, make changes, click save, and find out you aren't even allowed to edit the record because of the oppty stage. While I might be able to push back on the "display some fields" part - immediately returning to the Opp with a toast message might suffice; I'd need the business to confirm - So far I've not even been able to get it to work correctly when an edit is allowed and the edits are saved, as outlined in the question. Commented Jan 25, 2023 at 14:31
  • Okay, that's significantly more root-level-hacky than I'd trust myself to answer on (at least, not without a lot more attention than I have to spare this week), and I'm still not convinced the "disable edits on the opportunity line item, but not on the quote it's ostensibly synced to" is a sensible requirement, but that clarification helps. Commented Jan 25, 2023 at 18:00

You must log in to answer this question.

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