Showing posts with label Apex. Show all posts
Showing posts with label Apex. Show all posts

Sep 6, 2016

Lightning experience OR classic view, where am I?

Have you ever faced a problem of identifying in which experience user is opening your page (VFP)? Is it lightning or classic.



Well, here is the solution to it. There are two ways :

1) Via Apex

public boolean isLightningExperience()
{
 if(Apexpages.currentPage().getParameters().get('sfdcIFrameOrigin') != null)
        return true;
 return false;
}

2) Via JS on visualforce page

function isLightningExperience()
{
  if('{!$Currentpage.parameters.sfdcIFrameOrigin}' != '')
  return true;
  return false;
}

You can use two parameters to check this 'sfdcIFrameOrigin' and 'istdp'. Now you can easily identify in which experience the user is via your code and can manipulate the functionality accordingly. 

Happy Coding!!

Aug 30, 2016

Dynamic nth Level Hierarchy in Salesforce

This blog is somewhat related to my previous post but with bit easy implementation and more generic. We have encountered this implementation multiple time so thought of sharing it with all.

Ever thought of replicating this feature in any of your custom object?


Now the only complication is, in case of self lookup you don't know the end node and where your loop should stop (to think about the logic). So hope I will make it easy for you.

*Note : My blog code formatter is not working properly, so please check the spaces before using the code.

Step 1 : Create an apex class called HierarchyController, as shown below and save it.

public with sharing class DynamicHierarchyForBlogController 
{
 public String objectApiName {get;set;}
 public String fieldApiName {get;set;}
 public String nameField {get;set;}
 public String currentsObjectId {get;set;}
 public String topParentId {get;set;}
 public String jsonMapsObjectString {get;set;}
 private String jsonString;
 private Map> sObjectIdMap ;
 private Map selectedsObjectMap ;
 private Map allsObjectMap;

 public DynamicHierarchyForBlogController() 
 {
  currentsObjectId = Apexpages.currentPage().getParameters().get('id');
     sObjectIdMap = new Map>();
  selectedsObjectMap = new Map();
  allsObjectMap = new Map();
 }
 
 public String getjsonMapString()
 {
  retrieveInfo();
  return jsonString;
 }
 
 public void retrieveInfo()
 {
  String dynamicQuery = 'SELECT ID ,' + fieldApiName + ' , ' + nameField + ' FROM ' + objectApiName + ' ORDER BY ' + fieldApiName + '  LIMIT 50000';
  for(sObject obj: Database.query(dynamicQuery))
  {
   allsObjectMap.put(obj.id,obj);
  }

  if(currentsObjectId != null)
  {
   String dQuery = 'SELECT ID FROM ' + objectApiName + ' WHERE id =\'' + currentsObjectId +'\'';
   List objList = Database.query(dQuery);
   currentsObjectId = objList[0].Id;
   retrieveTopParent(currentsObjectId);
   retrieveAllChildRecords(new Set{topParentId});
   for(String str : sObjectIdMap.keySet())
   {
    selectedsObjectMap.put(str,allsObjectMap.get(str));
   }
   jsonString = JSON.serialize(sObjectIdMap);
   jsonMapsObjectString = JSON.serialize(selectedsObjectMap);
  }
 }

 public void retrieveTopParent(String sObjectId)
 {
  if(allsObjectMap.keySet().contains(sObjectId) && allsObjectMap.get(sObjectId).get(fieldApiName) != null)
  {
   topParentId = String.valueOf(allsObjectMap.get(sObjectId).get(fieldApiName));
   retrieveTopParent(topParentId);
  }
 }

 public void retrieveAllChildRecords(Set sObjectIdSet)
 {
  if(sObjectIdSet.size() > 0)
  { 
   Set allChildsIdSet = new Set();
   for(String str : sObjectIdSet)
   {
    Set childsObjectIdSet = new Set();
    for(sObject obj : allsObjectMap.values())
    {
     if(obj.get(fieldApiName) != null && String.valueOf(obj.get(fieldApiName)) == str)
     {
      childsObjectIdSet.add(obj.Id);
      allChildsIdSet.add(obj.Id);
     }
    }
    sObjectIdMap.put(str,childsObjectIdSet);
   }
   retrieveAllChildRecords(allChildsIdSet);
  }
 }
}

Step 2 : Now create a component called Hierarchy, as shown below and save it.

<apex:component controller="DynamicHierarchyForBlogController">
 
 <apex:attribute name="objectName" description="Name of Object." type="String" required="true" assignTo="{!objectApiName}"/>
 <apex:attribute name="FieldName" description="Name of the field of the object." type="String" required="true" assignTo="{!fieldApiName}"/>
 <apex:attribute name="RepersenterField" description="Name field of the object." type="String" required="true" assignTo="{!nameField}"/>
 <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
 
 <div id="parentDiv"></div>
 
    <style>
     #parentDiv ul:first-child
     {
      padding: 0;
     }
     #parentDiv li
     {
      list-style: none;
      padding: 10px 5px 0 5px;
      position: relative;
     }
  #parentDiv li span 
  {
      -moz-border-radius: 5px;
      -webkit-border-radius: 5px;
      /*border: 1px solid #999;*/
      border-radius: 5px;
      display: inline-block;
      padding: 3px 8px;
      cursor: pointer;
  }
  .selectedRecord
  {
   font-weight:bold; 
   color:blue;
  }
    </style>
    <script>
      var accountMap = JSON.parse('{!jsonMapString}');
      var accountValueMap = JSON.parse('{!jsonMapsobjectString}');
      var cClass = '';
  if("{!topParentId}".indexOf('{!$CurrentPage.parameters.id}') != -1)
   cClass = 'selectedRecord';
  var ul = '<ul><li id="{!topParentId}"  ><span class="' + cClass + '"  onclick="toggleChilds(\'' + '{!topParentId}' + '\',event)" ><b id="i{!topParentId}" class="minus" style="font-size: 1.5em;" >-</b>&nbsp;' +  accountValueMap['{!topParentId}'].{!RepersenterField} + '</span></li></ul>'  ;
  $(ul).appendTo("#parentDiv");
  appendUl('{!topParentId}','{!topParentId}');
      function appendUl(key)
      {
       $.each( accountMap[key], function( index, value ) 
       {
      var dclass = '';
      if(value.indexOf('{!$CurrentPage.parameters.id}') != -1)
       dclass = 'selectedRecord';
      var ul = '<ul class="' + key + '"><li id="' + value + '" ><span class="' + dclass + '" onclick="toggleChilds(\'' + value + '\',event)" ><b id="i' + value + '" class="minus" style="font-size: 1.5em;" >-</b>&nbsp;' + accountValueMap[value].{!RepersenterField} + "</span></li></ul>"  ;
      $(ul).appendTo("#" + key);
      if(value)
       appendUl(value);
   });
      }
      function toggleChilds(key,event)
      {
       $('.'+key).toggle('slow');
       $('#i'+key).toggleClass('minus');
       $('#i'+key).toggleClass('plus');
       if($('#i'+key).hasClass("minus")) 
        $('#i'+key).html("-");
         if($('#i'+key).hasClass("plus")) 
             $('#i'+key).html("+");
       event.stopPropagation();
      }
    </script>
</apex:component>

Step 3 : Now create a visualforce page, as shown below.

<apex:page standardcontroller="Account" showHeader="true" sidebar="true">
 <apex:pageblock title="Hierarchy">
  <c:DynamicHierarchyForBlog objectName="Account" FieldName="ParentId" RepersenterField="Name"/>
 </apex:pageblock>
</apex:page>
Open the page in the browser and pass a valid account id and the output will be a collapsible hierarchy as shown below.



This can plot the hierarchy of nth level and of any object. Post as comment if you have any questions.

Happy Coding!!

Feb 23, 2015

MailChimp Authentication In Salesforce - Easy Steps (Authentication Part 3)

I hope following post might have helped you in authentication:


So here is the third part of the series, authentication with MailChimp

The whole process of authentication with Mailchimp is divided into some simple steps :

Step 1:- First of all to authenticate with Mailchimp, you must have an account on Mailchimp if not then sign up here.

Step 2:- Now create an app by selecting your name under the logo and select account.


Step 3:- Here as you can see in the given image below, select registered app and register an app here.


Step 4:- Once you've entered the details for your Company and Application and saved them, your client_id and client_secret will be displayed at the bottom of the "edit" page for your application.

Note: - Keep in mind that Redirect Uri is the Uriof your page where you want to be redirected with the "code" parameter.

Step 5:- Now create an apex class and paste the below code in it.


publicwithsharingclassMailChimpIntegrationController
{
 public string client_id = 'Your ClientId';
 public string client_secret = 'Your ClientSecret';
 public string authorize_uri = 'https://login.mailchimp.com/oauth2/authorize';
 public string redirect_uri = 'https://c.na15.visual.force.com/apex/MailChimpIntegrationPage';
 
 publicMailChimpIntegrationController()
 {}
 
 publicPagereferenceauthorizeMailChimp()
 {
  authorize_uri = authorize_uri + '?response_type=code&client_id=' + client_id + '&redirect_uri=' + Encodingutil.urlEncode(redirect_uri , 'UTF-8');
PageReferencepg = newPageReference(authorize_uri) ;  
returnpg ;
 }
 
 publicvoidmailChimpAccessToken()
 {
  string code = ApexPages.currentPage().getParameters().get('code') ;  
  HttpRequestreq = newHttpRequest();  
req.setMethod('POST');  
req.setEndpoint('https://login.mailchimp.com/oauth2/token'); 
req.setHeader('content-type', 'application/x-www-form-urlencoded'); 
req.setHeader('Accept', 'application/json'); 
        String messageBody = 'grant_type=authorization_code&client_id=' + client_id + '&client_secret=' + client_secret + '&code=' + code + '&redirect_uri=' + Encodingutil.urlEncode(redirect_uri , 'UTF-8');
req.setHeader('Content-length', String.valueOf(messageBody.length()));  
req.setBody(messageBody);  
req.setTimeout(60*1000);  

        Http h = newHttp();  
        String resp;  
HttpResponse res = h.send(req);  
resp = res.getBody(); 

system.debug('+++++----json---with---Access-----token----++++++'+resp);
 }
}


Step 6:- Now create a visualforce page and paste the below code in it.



 
   
   
 


Step 7:- At last create a new remote site setting with value as below

-> Remote Site Name : MailChimp
-> Remote Site URL : https://login.mailchimp.com
-> Active : True


I hope now you can manipulate the code according to the need. As these simple buttons on VFP shows you how to authenticate and get the access tokens.

Cheers!

Feb 5, 2015

Image to PDF Converter in Salesforce

Okay, so this is one of my POCs I was doing recently where I need to convert an image to PDF. I can't disclose the full use case but hope it will help some.

So here is the solution in two simple steps :

1) First insert these three static resources (with the same names)

(i) Bootbox




2) Visualforce Page

 
    
    
    
    
    
    
    
    
    
    
      
 
     
        
        
    
    
    
    
 

    

 

(As it was just a POC so code is not clean yet, hope you can take care of that)

Okay so now all set to go, just hit the page and select any image you want to get converted in PDF. Multiple images can also be uploaded.

Cheers

Jun 12, 2013

Cow and Bull In Salesforce - Let's Brainstorm

Hope may of you are aware of the game Cow & Bull, but those who are not here are the rules

1) Computer will generate a 4 digit number which you need to guess in less than 10 chances
2) This number will not start from 0
3) All digits of the number will be unique (no digit will repeat)

For example:

1234 - is correct
0234 - is wrong
3445 - is wrong

Now user will input a 4 digit number which doesn't starts with 0 and all digits are unique. Computer will then compare with it's generated number and tell you the count of cows and bulls.

What is Cow and Bull

1) Cow: When digits of your number matches digits of computer's generated number on same index

For example: Computer generated > 4580

Your guess > 4619
Count of cows will be one as only one digit matches on same index.

If your guess is > 4689
Then count of cows will be 2 as "4" and "8" both matches at same index

2) Bull: When digit of your number matches digits of computer's generated number but not on same index

For example: Computer generated > 4580

Your guess > 6419
Count of bulls will be one as only one digit ("4") matches (but on same index).

If your guess is > 4689
Then count of bulls will be 2 as "4" and "8" both matches (but on same index)

So if you guessed 4851, then there is ONE cow ("4") and TWO bulls ("8" and "5")



Now it's time to use the brain, here is the site link: http://bmprojects-developer-edition.ap1.force.com/CB_CowAndBull


VFP:


<apex:page controller="CB_CowAndBullController" showHeader="false" sidebar="false">
    <apex:form id="FRM">
        <apex:pageBlock id="PB" title="Cow And Bull">
            
            <apex:pageMessage severity="INFO" escape="false">
                1) Enter 4 digit number which have all digits unique and is not starting from 0 <br/><br/>
                2) Cows: Digits from your number matches computer's number at same index <br/>
                e.g: You Enter -> 1234 and Computer Number -> 1960 <br/>
                1 matches on same index so it will be counted as cow <br/><br/>
                3) Bulls: Digits from your number matches computer's number but not on same index <br/>
                e.g: You Enter -> 1234 and Computer Number -> 9120 <br/>
                1 and 2 matches but not on same index so it will be counted as bull
            </apex:pageMessage>
            <apex:pageMessages id="PM"/>
            
            <apex:pageBlockButtons rendered="{!IF(showButton , true , false)}">
                <apex:commandButton value="Check C&B" action="{!CheckCandB}"/>
            </apex:pageBlockButtons>
            
            <!-- <apex:outputText value="Computer Generated Number : {!CompNumber}"/> -->
            
            <apex:pageBlockSection id="PBS1">
                <apex:pageBlockSectionItem id="PBSI1">
                    <apex:outputLabel value="Please Enter Your Number:"/>
                    <apex:inputText size="4" value="{!userEnteredNUmber}"/>
                </apex:pageBlockSectionItem>
            </apex:pageBlockSection>
            
            <apex:pageBlockTable rendered="{!IF(toDisplayWrapperLst.size > 0 , true, false)}" value="{!toDisplayWrapperLst}" var="wrap">
                <apex:column headerValue="Your Input" value="{!wrap.userInput}"/>
                <apex:column headerValue="Cows" value="{!wrap.cow}"/>
                <apex:column headerValue="Bulls" value="{!wrap.bull}"/>
            </apex:pageBlockTable>
        
        </apex:pageBlock>
    </apex:form>
</apex:page>


Apex Code:


public class CB_CowAndBullController
{
    public Integer CompNumber {get; set;}
    public Integer userEnteredNUmber {get; set;}
    //To maintain the user inputs
    public List<userInputResults> toDisplayWrapperLst {get; set;}
    //Flag to show the button which compare the user input with computer's generated number
    public boolean showButton {get; set;}
    
    public CB_CowAndBullController()
    {
        //Number entered by user
        userEnteredNUmber = 0 ;
        
        showButton = true ;
        
        toDisplayWrapperLst = new List<userInputResults>() ;
        
        //Generating 4 digit number which doesn't start with 0 and no number is repeated
        boolean flag = false ;
        while(!flag)
        {
            Integer tempVar = Integer.valueOf(Math.Random() * 10000) ;
            if(checkNumber(tempVar))
            {
                flag = true ;
                CompNumber = tempVar ;
            }
        }
    }
    
    private Boolean checkNumber(Integer num)
    {
        //Pattern for 4 digit number which doesn't start with 0 and no number is repeated
        Pattern nonZeroPattern = Pattern.compile('([1-9])(?!.*\\1)([0-9])(?!.*\\2)([0-9])(?!.*\\3)([0-9])(?!.*\\4)');
        Matcher nonZeroMatcher = nonZeroPattern.matcher(''+num);
        if(nonZeroMatcher.matches())
             return true;
        else
            return false ;
    }
    
    public PageReference CheckCandB()
    {
        if(checknumber(userEnteredNUmber))
        {
            //Logic to compare user input and computer's generated number
            Integer cow = 0 ;
            Integer bull = 0 ;
            String UEN = string.valueOf(userEnteredNUmber) ;
            String CGN = string.valueOf(CompNumber) ;
            
            for(Integer i = 0 ; i < UEN.length() ; i++)
            {   
                for(Integer j = 0 ; j < CGN.length() ; j++)
                {
                    if(UEN.subString(i , i+1) == CGN.subString(j , j+1))
                    {
                        if(i == j)
                            cow = cow + 1 ;
                        else
                            bull = bull + 1 ;
                    }
                }
            }
            toDisplayWrapperLst.add(new userInputResults(cow, bull, userEnteredNUmber)) ;

            if(cow == 4)
            {
                showButton = false ;
                ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO,'Congratulations! You guessed it right in ' + toDisplayWrapperLst.size() + ' chances.'));
            }
            else
            {
                if(toDisplayWrapperLst.size() > 9)
                {
                    showButton = false ;
                    ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'You failed to guess the number in 10 chances. Better luck next time.'));
                }
            }
        }
        else
        {
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'Please enter a 4 digit number which does not start with 0 and no number is repeated' ));
        }
        return null ;
    }
    
    //Wrapper to maintain number of cows, bulls and user input
    public class userInputResults
    {
        public Integer cow {get; set;}
        public Integer bull {get; set;}
        public Integer userInput {get; set;}
        
        public userInputResults(Integer c, Integer b, Integer ui)
        {
            cow = c ;
            bull = b;
            userInput = ui ;
        }
    }
}


Would love to hear the feedback.

Dec 27, 2012

Streaming APIs - Easy Code


Streaming API is useful when you want notifications to be pushed from the server to the client based on criteria that you define.

The sequence of events when using Streaming API is as follows: (explained in detail later)
1. Create a PushTopic based on a SOQL query. This defines the channel.
2. Clients subscribe to the channel.
3. A record is created or updated (an event occurs). The changes to that record are evaluated.
4. If the record changes match the criteria of the PushTopic query, a notification is generated by the server and received by the subscribed clients.

Before we get started, I recommend you to go through these topics:

1) Push Technology
2) Bayeux Protocol, CometD, and Long Polling


We will achieve this once we are done with all steps (given below):





Now follow these steps:

Prerequisites:
1) The “Streaming API” permission must be enabled -> "Your Name > Setup > Customize > User Interface"
2) The logged-in user must have “Read” permission on the PushTopic standard object to receive notifications.
3) The logged-in user must have “Create” permission on the PushTopic standard object to create and manage PushTopic records.
4) The logged-in user must have “Author Apex” permissions to create a PushTopic by using the Developer Console.


Step 1: Create an Object - In our case we will use Account

Step 2: Create a PushTopic
Use the Developer Console to create the PushTopic record. You can use either Developer Console or Workbench. If needed these records can be updated.

"Your Name > Developer Console"


PushTopic pushTopic = new PushTopic();
pushTopic.Name = 'RefreshAccounts';
pushTopic.Query = 'SELECT Id, Name FROM Account';
pushTopic.ApiVersion = 26.0;
pushTopic.NotifyForOperations = 'All';
pushTopic.NotifyForFields = 'Referenced';
insert pushTopic;


Step 3: Create Static resource

1. Download the CometD compressed archive (.tgz) file from http://download.cometd.org/cometd-2.2.0-distribution.tar.gz
2. Extract the following JavaScript files from cometd-2.2.0-distribution.tar.gz:
• cometd-2.2.0/cometd-javascript/common/target/org/cometd.js
• cometd-2.2.0/cometd-javascript/jquery/src/main/webapp/jquery/jquery-1.5.1.js
• cometd-2.2.0/cometd-javascript/jquery/src/main/webapp/jquery/json2.js
• cometd-2.2.0/cometd-javascript/jquery/src/main/webapp/jquery/jquery.cometd.js


File Name
Static Resource Name
cometd.js
Cometd
jquery-1.5.1.js
Jquery
json2.js
json2
jquery.cometd.js
jquery_cometd




Step 4: Test the PushTopic Channel

Here is the code sample

Visualforce Page


<apex:page id="PG" controller="StreamingAPIController">
<apex:form id="FRM">

    <apex:includeScript value="{!$Resource.cometd}"/>
    <apex:includeScript value="{!$Resource.jquery}"/>
    <apex:includeScript value="{!$Resource.json2}"/>
    <apex:includeScript value="{!$Resource.jquery_cometd}"/>

    <apex:actionFunction name="GetRefreshedAccounts" reRender="PB,PBT"/>

    <script type="text/javascript">
        (function($)
        {
            $(document).ready(function() {
                
                // Connect to the CometD endpoint
                $.cometd.init({
                    url: window.location.protocol+'//'+window.location.hostname+'/cometd/24.0/',
                    requestHeaders: { Authorization: 'OAuth {!$Api.Session_ID}'}
                });
                
                // Subscribe to a topic. JSON-encoded update will be returned in the callback
                // In this example we are using this only to track the generated event
                $.cometd.subscribe('/topic/RefreshAccounts', function(message)
                {
                    //You can use message as it will return you many attributes
                    //I am just using to track that event is generated
                    GetRefreshedAccounts();
                });

            });
        })(jQuery)
    </script>

    <apex:pageBlock id="PB">
        <apex:variable var="count" value="{!0}" />
        <apex:pageBlockTable id="PBT" value="{!getRefreshedAccount}" var="AllAcc">
            
            <apex:column headerValue="S.No.">
                <apex:variable var="count" value="{!count+1}" />
                {!count}
            </apex:column>
            <apex:column value="{!AllAcc.Name}" headerValue="Name"/>
            
        </apex:pageBlockTable>
    </apex:pageBlock>

</apex:form>
</apex:page>

Apex Class


public class StreamingAPIController
{
    //Everytime page is reRendered it will get refreshed values of account
    public List<Account> getRefreshedAccount
    {
        get
        {
            return [select Id, Name from Account LIMIT 50000] ;
        }
        set;
    }
    
    public StreamingAPIController()
    {
    }
}


This is very small and simple sample code, you can do a lot more with streaming APIs. Please refer these documents to learn more:

1) http://www.salesforce.com/us/developer/docs/api_streaming/api_streaming.pdf
2) http://www.salesforce.com/us/developer/docs/api_streaming/index.htm
3)http://wiki.developerforce.com/page/Getting_Started_with_the_Force.com_Streaming_API

Dec 22, 2012

Uploading Multiple Attachments into Salesforce - Simple Code

Okay, so here is the simple code to upload multiple attachments into Salesforce. Please note that I've used standard controller ("Account" in the code) so you need to pass the record Id in parameter. You can also change this according to your need as code is dynamic.

So first option allow you to select how many files you want to upload. Say, you have selected "5", then it will give you 5 options to select files and once you click on "Upload" it will upload the files as attachments to the associated record.



Visualforce Page Code:


<apex:page standardController="Account" extensions="MultipleUploadController">
    <apex:form>
        <apex:pageBlock title="Upload Multiple Attachment to Object">
            
            <apex:pageBlockButtons>
                <apex:commandButton value="Upload"  action="{!SaveAttachments}"/>
            </apex:pageBlockButtons>
            
            <apex:pageMessages id="MSG"/>
            <apex:actionFunction name="ChangeCount" action="{!ChangeCount}"/>
            
            <apex:pageblocksection>
                            
                <apex:pageBlockSectionItem>
                    <apex:outputLabel value="How many files you want to upload?"/>
                    <apex:selectList onchange="ChangeCount() ;" multiselect="false" size="1" value="{!FileCount}">
                        <apex:selectOption itemLabel="--None--" itemValue=""/>
                        <apex:selectOptions value="{!filesCountList}"/>
                    </apex:selectList>
                </apex:pageBlockSectionItem>
            
            </apex:pageblocksection>
            
            <apex:pageBlockSection title="Select Files" rendered="{!IF(FileCount != null && FileCount != '', true , false)}">
                <apex:repeat value="{!allFileList}" var="AFL">
                    <apex:inputfile value="{!AFL.body}" filename="{!AFL.Name}" />
                    <br/>
                </apex:repeat>
            </apex:pageBlockSection>
            
        </apex:pageBlock>
    </apex:form>
</apex:page>


Apex Code:


public class MultipleUploadController
{   
    //Picklist of tnteger values to hold file count
    public List<SelectOption> filesCountList {get; set;}
    //Selected count
    public String FileCount {get; set;}
    
    public List<Attachment> allFileList {get; set;}
    
    public MultipleUploadController(ApexPages.StandardController controller)
    {
        //Initialize  
        filesCountList = new List<SelectOption>() ;
        FileCount = '' ;
        allFileList = new List<Attachment>() ;
        
        //Adding values count list - you can change this according to your need
        for(Integer i = 1 ; i < 11 ; i++)
            filesCountList.add(new SelectOption(''+i , ''+i)) ;
    }
    
    public Pagereference SaveAttachments()
    {
        String accId = System.currentPagereference().getParameters().get('id');
        if(accId == null || accId == '')
            ApexPages.addmessage(new ApexPages.message(ApexPages.Severity.ERROR,'No record is associated. Please pass record Id in parameter.'));
        if(FileCount == null || FileCount == '')
            ApexPages.addmessage(new ApexPages.message(ApexPages.Severity.ERROR,'Please select how many files you want to upload.'));

        List<Attachment> listToInsert = new List<Attachment>() ;
        
        //Attachment a = new Attachment(parentId = accid, name=myfile.name, body = myfile.body);
        for(Attachment a: allFileList)
        {
            if(a.name != '' && a.name != '' && a.body != null)
                listToInsert.add(new Attachment(parentId = accId, name = a.name, body = a.body)) ;
        }
        
        //Inserting attachments
        if(listToInsert.size() > 0)
        {
            insert listToInsert ;
            ApexPages.addmessage(new ApexPages.message(ApexPages.Severity.INFO, listToInsert.size() + ' file(s) are uploaded successfully'));
            FileCount = '' ;
        }
        else
            ApexPages.addmessage(new ApexPages.message(ApexPages.Severity.ERROR,'Please select at-least one file'));
            
        return null;
    }
    
    public PageReference ChangeCount()
    {
        allFileList.clear() ;
        //Adding multiple attachments instance
        for(Integer i = 1 ; i <= Integer.valueOf(FileCount) ; i++)
            allFileList.add(new Attachment()) ;
        return null ;
    }
}


You can enhance the code if you like, as I've provided the basic code which is re-usable. Also you can change the object passed in standard controller and code will handle the rest. URL should have ID else you will get error on UI :-)

Say, I've saved my VFP code as "MultipleUpload", so my URL will be https://...../apex/MultipleUpload?id=XXXXXXXXXXXXXXX (account id in this code).

Happy Coding.

Dec 19, 2012

Reading Visualforce Page Code In Apex

Recently faced a strange requirement to change the Visualforce page code dynamically (apologies can't disclose the complete scenario)

So would like to share the small POC with code. Code will take Visualforce Page name as parameter and will return you the code written for that VFP as text. For example, this is my Visualforce Page saved with name "VisualforceCode"


<apex:page id="PG" controller="VisualforceCodeController">
<apex:form id="FRM">
    <apex:pageMessages id="PM"/>
    <apex:pageBlock id="PB">
        
        <apex:commandLink value="See Magic" action="{!DisplayCode}" >
            <apex:param assignTo="{!CurrentPageName}" value="{!$CurrentPage.Name}"/>
        </apex:commandLink>
        
        <br/> <br/>

        <apex:outputPanel id="OPT" rendered="{!showCodeSection}">
            <apex:outputLabel value="{!PageText}"/>
        </apex:outputPanel>
    
    </apex:pageBlock>
</apex:form>
</apex:page>


Now I want to read the code written in this page, so here is the working code which send page name as parameter in "UtilClass" to get the code as text:


public class VisualforceCodeController
{
    //To display section which hold code as text of VF page
    public boolean showCodeSection {get; set;}
    
    //To hold VF Code as text
    public String PageText {get; set;}
    
    //Hold current page name
    public String CurrentPageName {get; set;}
    
    public VisualforceCodeController()
    {
        CurrentPageName = '' ;
        showCodeSection = false ;
    }
    
    public PageReference DisplayCode()
    {
        if(CurrentPageName != '')
        {
            //Fetching VF code
            PageText = UtilClass.VFPageCode(CurrentPageName) ;
            showCodeSection = true ;
        }
        return null ;
    }
}


To get the visualforce page name I've used "{!$CurrentPage.Name}" which is a global variable

Here Util Class code:


//General Class with static methods
public class UtilClass
{
    //Method will take visualforce page name as parameter and returns the code written in it
    public static String VFPageCode(String PageName)
    {
        ApexPage testPage = new ApexPage();
        String PageText = '' ;
        
        if(PageName != '')
        {
            //Fetching visualforce page code
            testPage = [Select Id, Markup from ApexPage where name =: PageName];
            PageText = testPage.markup ;
        }
        return PageText ;
    }
}

There are many other methods you can use with "ApexPage" mentioned here. So if you want to update the VFP code from apex dynamically you can use "ApexPage"

Nov 23, 2012

Page Block Table With Dynamic Columns In Salesforce

This is something extensively used, but every time I need to look for some easy code.

So here is the solution (apologies as I've not covered the negative cases in code, and I hope you all are smart enough to take care of that). Requirement is to build the dynamic page block table with dynamic columns, but this is not it. It should be so dynamic that user can select the object and it's fields by himself and nothing should be hard-coded. So first of all I've provided a picklist with all objects (not all objects... why? Take a look at it Please Remove The System Objects From My sObject List)

Visualforce Page Code:

<apex:page controller="DynamicTableController">
<apex:pageBlock >
    <apex:form >
        <apex:actionFunction name="ObjectFileds" action="{!ObjectFields}"/>
        
        <apex:commandButton  value="Show Table" action="{!ShowTable}"/>
        
        <apex:pageBlockSection >
            <apex:pageBlockSectionItem >
                <apex:outputLabel value="Select Object"/>
                <apex:selectList multiselect="false" size="1" value="{!SelectedObject}" onchange="ObjectFileds();">
                    <apex:selectOption itemLabel="--None--" itemValue="--None--"/>
                    <apex:selectoptions value="{!supportedObject}" />
                </apex:selectlist>
            </apex:pageBlockSectionItem>
            
            <apex:pageBlockSectionItem >
                <apex:outputLabel value="Select Field"/>
                <apex:selectList multiselect="true" size="5" value="{!SelectedFields}">
                    <apex:selectOption itemLabel="--None--" itemValue="--None--"/>
                    <apex:selectoptions value="{!fieldLableAPI}" />
                </apex:selectlist>
            </apex:pageBlockSectionItem>
            
            <apex:pageBlockTable rendered="{!IF(ObjectList.size > 0 , true , false)}" value="{!ObjectList}" var="rec">
                <apex:column value="{!rec.Id}" rendered="{!IF(SelectedFields.size == 0 , true, false)}"/>
                <apex:repeat value="{!SelectedFields}" var="FieldLable">
                    <apex:column value="{!rec[FieldLable]}" rendered="{!IF(FieldLable != '--None--' , true, false)}"/>
                </apex:repeat>
            </apex:pageBlockTable>
            
            <apex:outputPanel rendered="{!IF(ObjectList.size < 1 , true , false)}">
                <apex:pageMessage severity="ERROR" summary="No records to display"/>
            </apex:outputPanel>
            
        </apex:pageBlockSection>
        
    </apex:form>
</apex:pageBlock>
</apex:page>


Apex Code (Class):

public class DynamicTableController
{
    //List displayed on UI
    public List<selectoption> supportedObject {get; set;}
    
    //Selected Object
    public String SelectedObject {get; set;}
    
    //Global describe
    Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();
    Set<String> objectKeys = gd.keySet();
    
    //Field Select List
    public List<SelectOption> fieldLableAPI {get; set;}
    
    //Selected fields to be displayed in table
    public List<String> SelectedFields {get; set;}
    
    //List to maintain dynamic query result
    public List<sObject> ObjectList {get; set;}
    
    
    //Constructor
    public DynamicTableController()
    {
        //Initialize
        supportedObject = new List<selectoption>() ;
        SelectedObject = '' ;
        fieldLableAPI = new List<SelectOption>() ;
        SelectedFields = new List<String>() ;
        ObjectList = new List<sObject>() ;
        
        //Get only reference to objects
        for(Schema.SObjectType item : ProcessInstance.TargetObjectId.getDescribe().getReferenceTo())
        {
            //Excluding custom setting objects
            if(!item.getDescribe().CustomSetting)
            {
                //Adding to list
                supportedObject.add(new SelectOption(item.getDescribe().getLocalName().toLowerCase() , item.getDescribe().getLabel() ));
            }
        }
        
    }
    
    //Get fields of selected object
    public void ObjectFields()
    {
        if(SelectedObject != '--None--')
        {
            //Creating sObject for dynamic selected object
            Schema.SObjectType systemObjectType = gd.get(SelectedObject);
            //Fetching field results
            Schema.DescribeSObjectResult r = systemObjectType.getDescribe();
                
            Map<String, Schema.SObjectField> M = r.fields.getMap();
            //Creating picklist of fields
            for(Schema.SObjectField fieldAPI : M.values())
            {
                fieldLableAPI.add(new SelectOption(fieldAPI.getDescribe().getName() , fieldAPI.getDescribe().getLabel())) ;
            }
        }
    }
    
    public void ShowTable()
    {
        //Creating dynamic query with selected field
        String myQuery = 'Select Id ' ;
        
        for(String field : SelectedFields)
        {
            if(field.toLowerCase() != 'id' && field.toLowerCase() != '--none--')
            myQuery += ','+ field + ' ' ;
        }
        
        //Limit is 100 for now you can change it according to need
        myQuery += ' from ' + SelectedObject + ' LIMIT 100' ;
        
        //Executing the query and fetching results
        ObjectList = Database.query(myQuery) ;
    }
}

Once user selects any object from the first picklist, filed picklist will be populated with all the field labels related to that object. Note, it's a multi-select picklist so user can select multiple fields. Once fields are selected and "Show Table" is clicked, page block table will display the field values (selected in field picklist) of all records (limit is 100 right now, you can change it according to your need).

There are some extra checks that needs to be implemented in code like "isQueryable" etc..

Sep 25, 2012

Creating Public Web-Service in Salesforce

We all are familiar with web services and we often use them. Now let's talk about other side of using web services by making them public so I don't need any authentication/passwords/SessionIds etc.

Recently I need to create a web service so it can used in a mobile app. Most of us know about Mobile SDK, REST, oAuth etc.. but in all I need to intake the credentials of salesforce organization to get access token or if am using web services then to get the session Id. But think about it, why end user will be concerned with the back-end/database? So all we need is a public web service which can be called to process our request.

So follow these simple steps:

1) Create a web service like this

global class DemoClass
{
    webService static string Method()
    {
        return 'DoSomething' ;
    }
}

2) Go to Site > Setup > App Setup > Develop > Sites > Select your Site > Give access of class "DemoClass" to site profile

3) Extract WSDL of your class, go to your class and then click "Generate WSDL". Now all we need to change the SOAP address.

Lets say, this is a snippet of my WSDL



Now we need to change the highlighted code like this:

This is the location:
https://ap1-api.salesforce.com/services/Soap/class/ankit/DemoClass

And our site URL is:

So our final location will be:
http://ankitarorasite-developer-edition.ap1.force.com/services/Soap/class/ankit/DemoClass

Now you can use this location in your WSDL and there will be no need of getting any access tokens or session Ids. Happy Coding.

Jul 30, 2012

Is There Better Way To Get Last Date Of Fiscal Quarter?

Recently it was requested to get the "Last Date" of present Fiscal Quarter. For e.g. if "Fiscal Year Start Month" is set to January (Setup > Administration Setup > Company Profile > Fiscal Year) and present month is Feb then date returned should be "31 March 2012"


SOQL is not the option as in the end I need to get the Date so after lot of brain storming end up with this solution, if this is not the best solution then other solutions suggestions are most welcomed.


So here is my apex method which returns me the last date of present fiscal quarter


//Returns last date of present fiscal quarter
public Date LastDateofCurrentFQ()
    {
        // Info : There are 4 Fiscal Quarter FQ( each of 3 months) in fiscal year 
        Organization  org = new Organization() ;
        org = [select FiscalYearStartMonth from Organization where id=:Userinfo.getOrganizationId()];
        Integer FiscalYearStartMonthIndex = org.FiscalYearStartMonth ; 

        // Month Index like january : 1 , february: 2 and so on 
        Integer CurrentMonthIndex = system.today().month();

        if(CurrentMonthIndex < FiscalYearStartMonthIndex )
            CurrentMonthIndex  = 12+ CurrentMonthIndex ;

        Integer DifferenceofBothMonths = CurrentMonthIndex - FiscalYearStartMonthIndex  ;
        Integer CurrentFiscalQuarterLastMonth  = 0; 

 if(0 < = DifferenceofBothMonths && DifferenceofBothMonths <= 2 ) //For first quarter
            CurrentFiscalQuarterLastMonth = FiscalYearStartMonthIndex  +2 ; 
        else if( 3 <= DifferenceofBothMonths && DifferenceofBothMonths <= 5) //For second quarter 
            CurrentFiscalQuarterLastMonth = FiscalYearStartMonthIndex  +5 ;
        else if( 6 <= DifferenceofBothMonths && DifferenceofBothMonths <= 8) // For third quarter
            CurrentFiscalQuarterLastMonth = FiscalYearStartMonthIndex  +8 ;
        else if( 9 <= DifferenceofBothMonths && DifferenceofBothMonths <= 11) // For fourth quarter
            CurrentFiscalQuarterLastMonth = FiscalYearStartMonthIndex  +11 ;

        if(CurrentFiscalQuarterLastMonth > 12)
            CurrentFiscalQuarterLastMonth  = CurrentFiscalQuarterLastMonth  - 12 ;         

        Date firstDateOFyear = date.newInstance(system.today().year(), 1, 1);
        Date LastDateofCurrentFQ  = date.newInstance(system.today().year(), 1, 1); 
        LastDateofCurrentFQ   = firstDateOFyear.addMonths(CurrentFiscalQuarterLastMonth).addDays(-1) ;
        return LastDateofCurrentFQ ;        
    }

Code is self explanatory, still if anything is not clear do reach me out.

Jul 27, 2012

Please Remove The System Objects From My sObject List

Question is "Can I remove the system objects from list returned by describe?"

I need to identify on which all objects I can create approval process. First and only thought is to use describe and get the list of sObjects, but the problem is describe returns too many other objects on which we can not create approval process like "campaignfeed", "caseteamrole" etc.. So what is the use of showing them all. Why not we can show the list of only those object which are displayed when we create approval from native UI?



Here is the solution for this big time problem. Use this apex code to get the sObject List (use describe in a smart way)

public class ApprovalEnabledObjectsController
{
    //List displayed on UI
    public List<selectoption> supportedObject {get; set;}
    
    //Constructor
    public ApprovalEnabledObjectsController()
    {
        //Initialize
        supportedObject = new List<selectoption>() ;
        
        //Get only reference to objects
        for(Schema.SObjectType item : ProcessInstance.TargetObjectId.getDescribe().getReferenceTo())
        {
            //Excluding custom setting objects
            if(!item.getDescribe().CustomSetting)
            {
                //Adding to list
                supportedObject.add(new SelectOption(item.getDescribe().getLocalName().toLowerCase() , item.getDescribe().getLabel() ));
            }
        }
        
    }
}


Visualforce Page (Test page to show the picklsit)



    
        
    




Special thanks to Amit Jain who helped me with this :-)

May 15, 2012

Static Resource URL in Apex

Question is how to get the Static Resource's URL in Apex, so below is the function which will return the relative URL (also supports namespace-resources)


public class StaticResourceURL
{
    //Pass the resource name
    public static String GetResourceURL(String resourceName)
    {
        //Fetching the resource
        List resourceList = [SELECT Name, NamespacePrefix, SystemModStamp FROM StaticResource WHERE Name = :resourceName];
                            
        //Checking if the result is returned or not
        if(resourceList.size() == 1)
        {
           //Getting namespace
           String namespace = resourceList[0].NamespacePrefix;
           //Resource URL
           return '/resource/' + resourceList[0].SystemModStamp.getTime() + '/' + (namespace != null && namespace != '' ? namespace + '__' : '') + resourceName; 
        }
        else return '';
    }
}


Use this in debug logs to verify :


System.debug(':::: ' + StaticResourceURL.GetResourceURL('StaticResourceName')) ;


*Please change the "StaticResourceName" with your Static resource name in above line

Jan 15, 2012

Integrating Google Maps in Salesforce

Requirement is to show the location of my Account on Google Maps. It looks difficult but actually it is very simple to implement.


Just create a new visualforce page with this code
<apex:page standardController="Account">

<script src="http://maps.google.com/maps?file=api">
</script>

<script type="text/javascript">

var map = null;
var geocoder = null;

var address = "{!Account.BillingStreet}, {!Account.BillingPostalCode} {!Account.BillingCity}, {!Account.BillingState}, {!Account.BillingCountry}";

function initialize() {
if(GBrowserIsCompatible())
{
  map = new GMap2(document.getElementById("MyMap"));
  map.addControl(new GMapTypeControl());
  map.addControl(new GLargeMapControl3D());
  
  geocoder = new GClientGeocoder();
  geocoder.getLatLng(
    address,
    function(point) {
      if (!point) {
        document.getElementById("MyMap").innerHTML = address + " not found";
      } else {
        map.setCenter(point, 13);
        var marker = new GMarker(point);
        map.addOverlay(marker);
        marker.bindInfoWindowHtml("Account Name : <b><i> {!Account.Name} </i></b> <br/> Address : "+address);
      }
    }
  );
}
}
</script>


<div id="MyMap" style="width:100%;height:300px"></div>
<script>
    initialize() ;
</script>

</apex:page>
As you can see that I have used standard controller so you need to pass the account Id in URL. Let's say if the page name is "GoogleMaps" then the URL will look something like this : ".../apex/GoogleMaps?id=YOUR_ACCOUNT_ID".






When you click on the balloon it will show you the Account name and the address, you can change it according to your need by changing the code of line "marker.bindInfoWindowHtml"


Use this page as in line visualforce page on native layout and enjoy the Google maps with Salesforce.


References
http://code.google.com/apis/maps/documentation/webservices/
http://code.google.com/apis/maps/index.html