Monday, January 6, 2014

Invoke Apex Code on Custom Button Click

Hello Accolades,

Description: Sometimes our requirement is like on custom button click, we want to invoke the Apex Class's method & perform some DML operations. There are different ways, but I think the following will be the best possible way.

Scenario: There will be a custom button on Standard Page, onClick of that CB you have to aggregate the Child fields on Standard/Custom object.

Steps to Follow:


1) Create a Custom Button named "Aggregate Child" on your object, Let's consider Stnadard Account as our object which will execute the JavaScript. In code panel you will import two Javascript files as follows:

{!REQUIRESCRIPT("/soap/ajax/14.0/connection.js")}
{!REQUIRESCRIPT("/soap/ajax/14.0/apex.js")}


2) Now next step will be create an Apex Class (Web Service) & Method, Call that method on this button Click.
So Let's say my controller Name is AccountController which will be global  & method will be aggregateChilds as Webservice.

global class AccountController1{
           webservice static void aggregateChilds(String accId){
                     Account accObje = new Account();
                     accObje = [SELECT id,(SELECT id FROM ChildObj__r) FROM Account WHERE id=: accID LIMIT 1];
                     System.debug(accObje.ChildObj__r.size());
                     
          /* 1) If you want to return the value. then Set the return type & get it in Javascript

              2) Perform DML Operation Whatever needed. */
              }
}

3) Call this method on Button's Javascript

{!REQUIRESCRIPT("/soap/ajax/14.0/connection.js")}
{!REQUIRESCRIPT("/soap/ajax/14.0/apex.js")}
var res=sforce.apex.execute("AccountController","aggregateChilds",{accId:"{!Account.Id}"})


4) That's about it. If you can Customize the code as per your requirement. If you face any issues, feel free to mail me at shingavi.a@gmail.com
Happy Coding!!

Thursday, January 2, 2014

Salesforce Batch Apex for Beginners

Hello Accolades,

This post is for the Beginner developer who want to learn & wants to explore with Batch Apex on Force.com Platform.

1) What is Batch Class/Batch Apex?
i) Basically Batch class allows us to define a single job that can be broken up into manageable batches that will be processed separately
ii) To override from the Salesforce's Governor Limit, we need to divide our job into chunks.

2) Components of Batch Apex?
To use batch Apex, you must write an Apex class that implements the Salesforce - provided interface Database.Batchable interface, and then invoke the class programmatically.

The Database.Batchable interface contains three methods that must be implemented: 

2-1) start method
Use the start method to collect the records or objects to be passed to the interface method execute. Use the Database.QueryLocator object when you are using a simple query (SELECT) to generate the scope of objects used in the batch job. If you use a querylocator object, the governor limit for the total number of records retrieved by SOQL queries is  bypassed.
Example - a batch Apex job for the Account object can return a QueryLocator for all account records (up to 50 million records) in an organization.
 

Syntax : global (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContext bc) {} 

2-2) execute method:
 Use this method to do all required processing for each chunk of data.

Syntax : global void execute(Database.BatchableContext BC, list<sObject> sObject){}

2-3) finish method
The finish method is called after all batches are processed. Use this method to send confirmation emails or execute post-processing operations like update on related object however we need to keep governor limits in mind.

Syntax : global void finish(Database.BatchableContext BC){}
 
Now Let's explore with Syntax:
Scenario : Create a Batch apex which will append the string “New Batch Processed” in all the existing Account Records.

1) Basic Skeleton

global class BatchClassName implements Database.Batchable<sObject>{

    global Database.QueryLocator start(Database.BatchableContext BC){}

    global void execute(Database.BatchableContext BC,List<sObject> scope){}

    global void finish(Database.BatchableContext BC){}
}


2) Fetch the records in start method

 global class BatchClassName implements Database.Batchable<sObject>{

    global Database.QueryLocator start(Database.BatchableContext BC){

            return Database.getQueryLocator('SELECT id,Name FROM Account');
     }

    global void execute(Database.BatchableContext BC,List<sObject> scope){}

    global void finish(Database.BatchableContext BC){}
}


3) Append the “New Batch Processed” to all Account's Name:

global class BatchClassName implements Database.Batchable<sObject>{

    global Database.QueryLocator start(Database.BatchableContext BC){

            return Database.getQueryLocator('SELECT id,Name FROM Account');
     }

    global void execute(Database.BatchableContext BC,List<sObject> scope){

           
           for(sObject sObjItr : scope){
                     sObjItr.put('Name','New Batch Processed'+' '+String.valueof(sObjItr.get('Name')));
           }
           update scope;
   }

    global void finish(Database.BatchableContext BC){}
    }


4) Execute the Batch Class

Id batchJobId = Database.executeBatch(new BatchClassName(),Batch Limit); 
Ex. Id batchJobId = Database.executeBatch(new BatchClassName(),10); 

That's about it, Now check Account Names, the "New Batch Processed " is appended to all account names. 
This is basic about the Batch Class, You can call the batch class in Apex Classes, VF controller, Scheduled Classes or using Developer Console. You can also call the Batch Class in Trigger, but It is not recommended to call Batch Class in Trigger.
Hope this will help, If you have any query, feel free to drop me a mail @ shingavi.a@gmail.com.

Happy Coding!! :)

Thursday, December 26, 2013

Conga Composer for Beginers

Hello Accolades,

I am working on one of the best App on AppExchange i.e Conga Composer from last couple of weeks. Conga Composer is basically used to create Contracts, Presentations, Reports. When I searched about the core functionality I didn't find some simple tutorials, So I am writing this blog to simplify the way to handle your requirement with Conga Composer.

Installing Conga Composer in your Org :
Click on the following link & Click on "Get It now"
 Conga Composer AppExchange Package Link

Create a Custom button on Opportunity :
When you install the Conga Composer, you will get Standard button named "Conga Composer" However If your Client want some custom name like "Create Contract", "Create Presentation" So You need to create a Custom button or Link & Add this button on Page Layout.

On button you should write the following basic code to redirect request to Conga Composer.

https://www.appextremes.com/apps/Conga/Composer.aspx
?sessionId={!API.Session_ID}
&serverUrl={!API.Partner_Server_URL_80}
&id={!Opportunity.Id}




To add the Custom parameters to your link, Please follow the link :
Conga Composer Custom Parameter
Your can use the Custom parameter on the link for additional functionality like Background Mode, Email the Merge Document, Logging the Activity, Set SCHP parameters etc.

Till, you have successfully created a basic stuff around Conga Composer.


Create Conga Merge Formulas:
Now, we will move towards to create the Conga Merge formulas:

Click on the Custom/Standard button that you added on Opportunity then a window will be popup 



Click on Template Builder - Click a field name to copy it to the clipboard, then paste it into a Word, Excel, PowerPoint or PDF merge field. The data would come up from Master Dataset or Report Dataset.


You have successfully created your basic document. Now click on "Choose a template from your local computer" radio button, browse your document & click on Merge button.
It will populate the data in your document.

That's about the basics of Conga Composer, If you have any query, Please feel free to drop me a mail at shingavi.a@gmail.com.




Email Template Example

Hello Accolades,

The following code will explain you how to display Email Templates on VF page & re-render with respect to folder selection.

VF Page :
<apex:page controller="EmailTemplateController">
     <apex:form>
        <apex:pageBlock title="View Email Template" id="emailTemplateBlock">
            Select Email Template Folder:
            <apex:selectList value="{!selectedEmailTemplateFolder}" multiselect="false" size="1">
                <apex:selectOptions value="{!emailTemplateFolderOpts}" />
                <apex:actionSupport event="onchange" action="{!refreshEmailTemplateSection}" rerender="emailTemplateBlock" />
            </apex:selectList>
            <br/><br/>
            Select Email Template:
            <apex:selectList value="{!selectedEmailTemplate}" multiselect="false" size="1">
                <apex:selectOptions value="{!emailTemplateOpts}" />
                <apex:actionSupport event="onchange" action="{!refreshEmailTemplateSection}" rerender="emailTemplateBlock" />
            </apex:selectList>
            <br/><br/>
            <apex:outputPanel id="emailTemplateContentPanel" rendered="{!NOT(ISNULL(chosenEmailTemplate))}">
                <p><b>{!chosenEmailTemplate.Name} - Subject:</b> {!chosenEmailTemplate.Subject}</p>
                <pre>{!chosenEmailTemplate.Body}</pre>
            </apex:outputPanel>
        </apex:pageBlock>
    </apex:form>
</apex:page>

Controller : 
public class EmailTemplateController{

    private List<EmailTemplate> allEmailTemplates;
    private List<Folder> allEmailTemplateFolders;
    public String selectedEmailTemplateFolder {public get; public set;}
    public String selectedEmailTemplate {public get; public set;}
    public EmailTemplate chosenEmailTemplate {public get; private set;}

    public SomeController() {
        allEmailTemplates = [select Id, Name, Subject, Body, FolderId from EmailTemplate order by Name asc];
        allEmailTemplateFolders = [select Id, Name from Folder where Type = 'Email' order by Name asc];
        System.debug(allEmailTemplates+'======='+allEmailTemplateFolders);
    }

    public List<SelectOption> getEmailTemplateFolderOpts() {
        List<SelectOption> opts = new List<SelectOption>();
        opts.add(new SelectOption('null', ' - Select - '));
        for ( Folder f : allEmailTemplateFolders )
            opts.add(new SelectOption(f.Id, f.Name));
        // add an option for templates in the Unfiled Public folder
        opts.add(new SelectOption(UserInfo.getOrganizationId(), 'Unfiled Public'));
        return opts;
    }

    public List<SelectOption> getEmailTemplateOpts() {
        List<SelectOption> opts = new List<SelectOption>();
        if ( selectedEmailTemplateFolder != null ) {
            opts.add(new SelectOption('null', ' - Select - '));
            Id selectedId = (Id) selectedEmailTemplateFolder;
            for ( EmailTemplate et : allEmailTemplates ) {
                if ( et.FolderId == selectedId )
                    opts.add(new SelectOption(et.Id, et.Name));
            }
        }
        return opts;
    }

    public PageReference refreshEmailTemplateSection() {
        // this is a bit ugly, but a consequence of not being able to set a SelectOption's value to null
        if ( selectedEmailTemplateFolder == null || selectedEmailTemplateFolder == 'null' ) {
            selectedEmailTemplateFolder = null;
            selectedEmailTemplate = null;
        }
        if ( selectedEmailTemplate == null || selectedEmailTemplate == 'null' ) {
            selectedEmailTemplate = null;
            chosenEmailTemplate = null;
        } else {
            Id selectedId = (Id) selectedEmailTemplate;
            for ( EmailTemplate et : allEmailTemplates ) {
                if ( et.Id == selectedId ) {
                    chosenEmailTemplate = et;
                    break;
                }
            }
        }
        return null;
    }
}

Happy Coding!!