Thursday, January 29, 2015

Avoid Multiple Clicks on Longer Loading VisualForce Page

For this you'll need a Static asset like this (in my case it's a "waiting/loading" animated gif):


You'll wrap some divs around your buttons and your animate gif:
<apex:pageBlockButtons >
    <div class="waitingGifDiv" >
        <apex:image id="WaitingGif" value="{!URLFOR($Resource.WaitingGif)}" width="50" height="50" style="float:center-right; "/>
    </div>
    <div class="SubmitButtonDiv">
        <apex:commandButton id="SubmitButton" styleClass="SubmitButton" value="Submit Case" action="{!submitCase}" />
    </div>
</apex:pageBlockButtons>

Then you'll need just a little javascript (in this case with a little jquery help) to first hide the animated gif when the page loads.  Then when the user clicks the button, hide the button and unhide the animated gif.  Simple, right?
  
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script >
      
    j$ = jQuery.noConflict();
    j$(document).ready(function() {
       //code when page is ready 
       j$('.waitingGifDiv').hide();
       
       j$('.SubmitButton').on('click',function() {
           j$('.waitingGifDiv').show();
           j$('.SubmitButtonDiv').hide();
        });
    });
</script>
    

Tuesday, January 20, 2015

Questions for Client BEFORE accepting an engagement.

How many projects?

Do you have a SFDC admin?

Do you have a project manager for each project?  Do you have a project manager at all?  Who is it?

Do you have a business analyst? How many? Who? Dedicated to which project(s)?

Who decides priority on the projects?

Do you have change control?  How does it work?

Do you have a deployment policy?  What is it?

Do you have a documentation policy?  What is it?

Do you have a QA team?

If I am to be the SFDC developer, and admin, and business analyst, and QA, and project manager...do you understand that it multiplies the amount of time it will take me to get things done?

Will SFDC need to integrate with other systems?  What systems?  How is the manager, BA, admin, developer for those systems? It there QA environments for those systems?

Who was the previous SFDC admin/dev/ba/pm?  Why are they no longer on the project?



NOTE: Also, go to http://www.glassdoor.com/ to research the company. Read reviews of what it's like working for the company.  Get the main gist of the complaints and tactfully address those during the meeting.

Thursday, January 15, 2015

Upload Pictures to Case with Apex

Uploading a picture to a Case programatically is a multi-stage process.

First, you'll need a custom field on the Case with a Data Type of Rich Text Area.  In this example, we have one called Photo__c.

You'll also need the "apex:inputfile" component in you Visual Force code, like so:
  

<table>
  <tr>
    <th>Photo #1 (Optional):</th>
    <td><apex:inputfile filename="{!photoForUploadName}" id="photoForUpload" value="{!photoForUpload}"></apex:inputfile></td>
  </tr>
  <tr>
    <th>Photo #2 (Optional):</th>
    <td><apex:inputfile filename="{!photoForUploadName2}" id="photoForUpload2" value="{!photoForUpload2}"></apex:inputfile></td>
  </tr>
</table>

You will also need a Document Folder to use for storing the images (in this example, we use "QAPhotos").

Please note in the code the comments regarding the imageURL

Your apex code will first up save the image to your chosen folder in your Documents object.  It will then based on the newly generated id and create an html string using references to your images as the scr attribute in an img tag:
  
<br>
    public Blob photoForUpload { get; set; }
    public String photoForUploadName { get; set; }
    
    public Blob photoForUpload2 { get; set; }
    public String photoForUploadName2 { get; set; }

    public PageReference createCase() {

               Folder QAPhotosFolder = [Select Id From Folder where Name = 'QAPhotos'];
        
               if(photoForUpload != null){
                    System.Debug('photoForUploadName: ' + photoForUploadName);
                    String photoExtension = photoForUploadName.substring( photoForUploadName.lastindexof('.')+1);
                    System.Debug('photoExtension : ' + photoExtension );
                    Document d= new Document();
                    d.name = 'Photo: ' + photoForUploadName ;
                    d.body=photoForUpload ; // body field in document object which holds the file.
                    d.folderid= QAPhotosFolder.Id;  //folderid where the document will be stored insert d;
                    d.IsPublic = true;
                    d.contenttype='image/' + photoExtension ;
                    d.type= photoExtension ;
                    insert d;
                    /* 
                       Label.Global_DocBaseURL is a label being used as a Global Variable
                       The value of oid will depend on your instance.
                       Open an image in you Documents, to see what your url and oid should be
                       We are using the value: https://c.cs9.content.force.com/servlet/servlet.ImageServer?id={DocumentId}&oid=00DX000000X51xX
                    */
                    String imageURL = Label.Global_DocBaseURL.replace('{DocumentId}',d.id);
                    c.Photo__c = 'Photo 1: <br/><img src="' + imageURL + '"></img>' ;
                }
                
                if(photoForUpload != null){
                    String photoExtension = photoForUploadName2.substring( photoForUploadName2.lastindexof('.')+1);
                    Document d= new Document();
                    d.name = 'Photo: ' + photoForUploadName2 ;
                    d.body=photoForUpload2 ; // body field in document object which holds the file.
                    d.folderid= QAPhotosFolder.Id;  //folderid where the document will be stored insert d;
                    d.IsPublic = true;
                    d.contenttype='image/' + photoExtension ;
                    d.type= photoExtension ;
                    insert d;
                    
                    String imageURL = Label.Global_DocBaseURL.replace('{DocumentId}',d.id);
                    c.Photo__c = c.Photo__c + '<br/><br/>Photo 2: <br/><img src="' + imageURL + '"></img>' ;
                }

                // Insert the case
                INSERT c;
        
    }

Create Knowledge Base Article, Publish It (Or Not), and Attach It To A Case

One best practice for Case Management (Service Cloud) is to attach a Knowledge Base Article when closing a case.

This code is for a circumstance where we want an external VF page to display the Case info and allow the user to enter the Knowledge Base Information that resolves the Case.  The KB info gets saved to SFDC.  Then the association is made between the KB Article and the case.

In our case, we did not want the Article published right away.  This allowed a second set of eyes to review the article, make modifications if necessary, and then publish it.  But the code below shows how to programatically publish the article.
  

public Case c { get; set; }

// QA_Corrective_Action__kav is an ArticleType.  Remember, each Knowledge Base Article gets its own object based on the ArticleType
public QA_Corrective_Action__kav CorrectiveAction { get; set; }

public PageReference updateCase() {
        
        //Clean up the URL a bit
        String UrlName = CorrectiveAction.title.replace(' ','-');
        UrlName = UrlName.replace('#','');
        UrlName = UrlName.replace('&','');
        UrlName = UrlName.replace('?','');
        CorrectiveAction.UrlName = UrlName ;

        //1st Create the article
        insert CorrectiveAction;

        KnowledgeArticleVersion kav = [Select Id, KnowledgeArticleId from KnowledgeArticleVersion  where PublishStatus = 'Draft' and Id=: CorrectiveAction.Id];
        
        //2nd Publish the article (if you want)
        //Comment Out Line Below if you do NOT want the Article published yet.
        KbManagement.PublishingService.publishArticle(kav.KnowledgeArticleId , true);

        
        CaseArticle cArticle = new CaseArticle();
        cArticle.CaseId = c.Id;
        cArticle.KnowledgeArticleId = kav.KnowledgeArticleId ;

        //3rd Create the association between the Article and the Case
        insert cArticle;
        
        
        return new PageReference('/apex/QACaseUpdateThankYou');
        
    }