1

I need to add two buttons to the Opportunity page, one labelled "Close Opportunity (Won)" and "Close Opportunity (Lost)". Previously I know this was available by URL hacking the opportunity page, but that's since been patched by Salesforce.

I've tried using an Apex class that gets the opportunity from a URL parameter, changes the StageName, then saves. But I can't return to the detail page because "Constructor must not return a value". Meaning I can't redirect once the code has run without requiring user input. If the user has to press another button to go back to the detail page then they might as well just edit the field manually.

Here is my Apex code:

 public class OpportunityCloseButtonController {

     public string OppId { get; set; }
     public string IsWon { get; set; }

     public OpportunityCloseButtonController() {

         //Get url params
         OppId = ApexPages.currentPage().getParameters().get('oid');
         IsWon = ApexPages.currentPage().getParameters().get('w');

         if (OppId == null || IsWon == null) {
             ApexPages.Message newMsg = new ApexPages.Message(ApexPages.Severity.ERROR, 'One or more parameters missing! Contact your Salesforce administrator.');
             ApexPages.addMessage(newMsg);
         } else {
             List<Opportunity> oList = [SELECT Id, StageName FROM Opportunity WHERE Id = :OppId LIMIT 1];
             if (oList.size() > 0) {
                 Opportunity currentOpp = oList[0];

                 if (IsWon == '1') {
                     currentOpp.StageName = 'Closed Won';
                 } else {
                     currentOpp.StageName = 'Closed Lost';
                 }

                 insert currentOpp;

                 PageReference oppPage = new ApexPages.StandardController(currentOpp).view();
                 oppPage.setRedirect(true);
                 return oppPage;

             } else {
                 ApexPages.Message newMsg = new ApexPages.Message(ApexPages.Severity.ERROR, 'The specified opportunity could not be found.');
                 ApexPages.addMessage(newMsg);
             }
         }
     }
 }

I totally understand why Salesforce removed the URL hacking ability, but so far I can't find anything to replace the functionality.

1 Answer 1

2

I have done this in two different ways.

With page action

Create an extension to the Opportunity standard controller with two action methods:

public class OpportunityButtonExtension {
    Opportunity Opp;
    (ApexPages.StandardContoller Ctrl;
    public OpportunityButtonExtension(ApexPages.StandardContoller ctrl) {
         Opp = (Opportunity) ctrl.getRecord();
         this.Ctrl = ctrl;
    }

    public PageReference CloseLostOpp()
    {
        //do the database thing to close the opp
        return Ctrl.View();
    }

    public PageReference CloseWonOpp()
    {
        //do the database thing to close the opp
        return Ctrl.View();
    }

}

And then two VF pages:

<apex:page standardController="Opportunity" extensions="OpportunityButtonExtension" 
           action="{!CloseLostOpp}" />

and

<apex:page standardController="Opportunity" extensions="OpportunityButtonExtension" 
          action="{!CloseWonOpp}" />

If your Close-Lost and Close-Won buttons point to these VF pages, the user experience will be pressing the button, seeing the screen flash, and seeing the Opportunity view page reload with the opp closed. The VisualForce page loads, and immediately runs the method set as the action parameter.

With a javascript button

I'm not going to type out the code for this, but javascript can run on a button, update the database using API, and refresh the page.

I'm surprised your controller works. Can we do DML in constructors now? We didn't used to be able to. Plus you appear to be inserting an Opp that you just pulled out of the database, rather than updating it.

You must log in to answer this question.

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