Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Thursday, October 24, 2013

Custom Button to Run Your Entry Criteria before Approval Submission

A sorely lacking feature with Salesforce approvals is the entry criteria rejection message.  If your record does not meet the entry criteria for a given approval process, you get a very generic

Unable to Submit for Approval
This record does not meet the entry criteria or initial submitters of any active approval processes. Please contact your administrator for assistance. 


with no indication of what is missing!  Users hate this.  I mean, HATE this.  They did not configure the approval process and so they've got no idea why they can't submit for an approval.  If the organization is large enough, the sales ops and/or IT help desk gets involved.  This to me is total lunacy and I see it everywhere.  Imagine the productivity you could restore if you provided your users with some meaningful information.  There is an idea you can vote up, if you agree.

There are some options to work around this limitation in the product.  One that I've been playing with is the idea of moving the entry criteria rules into one or many validation rules that only run when a field is set.  For example, you could have a Validated__c flag and create "entry criteria" validation rules to only allow it be set if your entry criteria are met. The flag could then be used by the approval process entry criteria and moves the logic back to the object where it can be surfaced.  Depending on your business, you could use workflows/triggers to uncheck the flag, should something change prior to approval submission.

It was pretty easy to move the entry criteria into validation rules but where I struggled was getting a button to set the field for me and still display the validation rule errors on the standard layout.  I was thinking that a "Validate" button would be more intuitive than setting the flag manually, so here's what I tried:

  1. Button click -> javascript to set field and save 
    • validation rule errors only captured in js but raised through an alert box
  2. Button click -> apex class to set field and save
    • validation rule errors only captured in js, again, raised in alert box
  3. Button click -> url params to set field and auto-save(?!)
    • almost there!

With options 1 and 2 the javascript is only able to surface the errors with an alert.  If your rules are simple, this is probably viable and acceptable for your users.  However, if you have 10 fields that are required for an approval process, your users are probably not going to write down each of the fields they need, then dismiss the alert, then fix the fields and submit.

With option 3, I was looking around to see if there were any non-visualforce options when I came across this article.  The idea was simple: use a custom button to invoke the edit mode for the record and prepopulate the Validate__c flag.  Additionally,  if you add Save=1 to your url, Salesforce could automatically save the record!  It only took a few minutes to configure and everything worked beautifully except the auto-save.  Apparently, Salesforce has disabled the Save parameter, so for now, our users have to click the Validate button, then Save.  Not bad.

The bottom line is that there are options to improve the usability of the entry criteria in your approval process.  You do not have to live with the generic error and you can certainly improve the productivity of your team by moving some of the logic into validation rules.



Thursday, October 3, 2013

The Create PDF button on Quote

I was asked about the ability to restrict the creation of a PDF for a given quote until a couple business rules had been met.  As I thought about the solution, a couple ideas came to mind:

1. Add a record type for the ok Quotes and assign that record type a new layout that includes the Create PDF button.  Remove the Create PDF from the other page layout.
2. Modify the behavior of the existing Create PDF button to check the status first.
3. Create a new VF page to replicate the Create PDF functionality.

Given the timing and other project considerations, I opted for #2, if it was feasible.  I knew that #1 would work but I was worried about introducing a record type and then having to roll it back when another quote-related project went live.

To start, I had to figure out if I could see the code that the out-of-box button was calling to render the PDF.  With chrome it was pretty easy to inspect the element and see the code the button was calling.

With a minor bit of additional javascript, the quote's status can be interrogated first and an informational alert raised, if certain business criteria are met:

/*********************************************************************
if('{!Quote.Status}'!= 'XYZ' ) 
{
// do some business logic...
var isOk = true;  
} if(isOk) 

var pdfOverlay = QuotePDFPreview.quotePDFObjs['quotePDFOverlay']; 

pdfOverlay.dialog.buttonContents = "<input value=\'Save to Quote\' class=\'btn\' name=\'save\' onclick=\"QuotePDFPreview.getQuotePDFObject(\'quotePDFOverlay\').savePDF(\'0\',\'0\');\" title=\'Save to Quote\' type=\'button\' ><input value='Save and Email Quote' class='btn' name='saveAndEmail' onclick=\"QuotePDFPreview.getQuotePDFObject(\'quotePDFOverlay\').savePDF(\'1\');\"; title='Save and Email Quote' type='button' ><input value=\'Cancel\' class=\'btn\' name=\'cancel\' onclick=\"QuotePDFPreview.getQuotePDFObject(\'quotePDFOverlay\').close();\" title=\'Cancel\' type=\'button\' >"; 

//change this to use the correct template for your business/environment!! 
pdfOverlay.summlid = 'XXXXXXXXXXXXX'; 

pdfOverlay.setSavable(true); 

//change this to use the quote id 
pdfOverlay.setContents('/quote/quoteTemplateDataViewer.apexp?id={!Quote.Id}','quote/quoteTemplateHeaderData.apexp?id={!Quote.Id}'); 

pdfOverlay.display(); 

else 

//raise an alert to let the user know about some business rule
alert('The Quote requires XYZ before the PDF can be generated.'); 
}

*************************************************************/




Tuesday, June 18, 2013

MultiSelect and JQuery/Javascript

I had a requirement to give users a way to quickly select a couple of values in a multi-select picklist based on some other value they had previously selected on the form.  In our case, if the selected Language was X, then pick Region 1, Region 3, and Region 4 from the multi-select picklist automatically.

This one took a while to piece together so hopefully this will help someone out.

On my VF page, I created an anchor tag to act like a "Command Link":


  <a href="javascript:void(0);" id="selectAllRegions">[Select All Regions for Language]</a></span>

Using some jquery, I catch the click as follows:

  j('#selectAllRegions').click(function () {
        selectRegions('{!$Component.regionsMS}');

        });

The regionsMS id is the id of your multiselect apex:inputfield.

The "selectRegions" function does the following:

function selectRegions(objId){
    var multiSelect;
    var unSelectedId = objId + "_unselected";
    var selectedId = objId + "_selected";
   
    multiSelect = document.getElementById(unSelectedId);
        for (i = 0; i < multiSelect.options.length; i++) {
            if(multiSelect.options[i].text == "Region 1"){
            multiSelect.options[i].selected = true;}
        }

        javascript:MultiSelectPicklist.handleMSPSelect(objId);
}

The key to making this work was this last function, which came up in a search here (there's some other NSFW stuff there, just fyi).  If you use firebug or chrome's developer tools, you'll see how the script interacts with the elements that make up the multiselect control.

And there you have it - when you click the link "Select All Regions for Language", Region 1 is selected.  All that needs to be done now, is evaluate the selected language and then change which region values are selected.