Tuesday, December 15, 2015

Dynamically select the recordtype by custom javascript Button

When i tried to create a contact record without selection of record type it is not possible from the standard button. So i came up with some custom java script button.

To create a custom button navigate to Setup- Customize - Contacts - Buttons, Links, and Actions
Click on Buttons, Links, and Actions and click new Button or link. Give the Name and api name and select the Display Type as List Button, behavior as Execute javascript and content source as onclick javascript.

Paste the below code in the space provided. change the recordtype name to your record type name.
{!REQUIRESCRIPT("/soap/ajax/33.0/connection.js")} 
{!REQUIRESCRIPT("/soap/ajax/33.0/apex.js")} 

var qr = sforce.connection.query("SELECT Id FROM RecordType WHERE SobjectType ='" + "Contact" + "'" +" AND DeveloperName = '"+"RecordTypeName"+ "'"); 
var records = qr.getArray("records"); 

if(!records.isEmpty)
{ 
 var redirecturl="/003/e?retURL={!Account.Id}&con4={!Account.Name}&con4_lkid={!Account.Id}&RecordType="+qr.records.Id; 
 window.location=redirecturl; 
}

Tuesday, October 13, 2015

Download csv File using Visual force page

I tried downloading a csv file from a visualforce page.

In the code below i am querying contacts object and downloading the query result in csv


 {!a.FirstName},{!a.lastName}


Apex Class:
public class Sample
{   
    public List contacts {get;set;}
    public pageReference fetch()
    {
         contacts = [SELECT Id,firstname,lastname FROM Contact limit 20];
        return null;
    }    
}

Display Matrix Report in Visualforce page

Using the jsforce i recently worked on analytics to display Matrix reports in visualforce page. Querying the tabular Report and accessing the fields and displaying in visualforce pages.





Display reports in visualforce page

Using the jsforce i recently worked on analytics to display reports in visualforce page. Querying the tabular Report and accessing the fields and displaying in visualforce pages.




    
    
    
    

Sunday, October 11, 2015

Create Sobject Records from JavaScript using Jsforce Library

Create a vf page and past the below code 

    
    
    
     
    
    

Friday, September 11, 2015

JSforce that you can easily run the SalesforceAPI from JavaScript

JSforce that can run easily the SalesforceAPI from JavaScript. It is very convenient to try using Visualforce page of Developer environment.

Download the jsforce jibrary and create in static resource with name jsforce
https://cdnjs.cloudflare.com/ajax/libs/jsforce/1.5.0/jsforce.js


<apex:page>
    <apex:includeScript value="{!$Resource.jsforce}" />
    <apex:form>
        <apex:commandButton value="Get Count" onclick="return doClick();" />
    </apex:form>
    <script>
        var conn = new jsforce.Connection({accessToken: '{!$Api.Session_Id}'});
        function doClick () {
            var soqlQuery = 'SELECT Id, Name FROM Account';
            conn.query (soqlQuery, function (err, res) {
                if (err) {
                    alert (err);
                }
                alert (res.records.length);
            });
            return false;
        }
    </script>
</apex:page>

Wednesday, September 9, 2015

IP Address Geolocation

If you would like to know your ip address location based on the user ip address. here is best option you can go with.

I have created a visualforce page and an apex controller that makes a callout to external application with the user logged in ip address and will get back the response and displays in vf page. 

Add the endpoint url to Remote Site Settings 
http://www.telize.com

Vf page:
<apex:page controller="FindIpAddress" action="{!getipaddress}">
Country:{!country}<br/>
Isp:{!isp}<br/>
IP:{!ip}<br/>
Latitude:{!latitude}<br/>
Longitude{!longitude}<br/>
TimeZone: {!timezone}<br/>
</apex:page>


Apex Class
public class FindIpAddress {
    public String country {get;set;}
    public String isp {get;set;}
    public String ip {get;set;}
    public integer latitude {get;set;}
    public integer longitude {get;set;}
    public String timezone {get;set;}
 
 public void getipaddress() {
  string ReturnValue = '';  
  ReturnValue = ApexPages.currentPage().getHeaders().get('True-Client-IP');
  if (ReturnValue == '' || ReturnValue == null) {
   ReturnValue = ApexPages.currentPage().getHeaders().get('X-Salesforce-SIP');
  } 
  if (ReturnValue == '' || ReturnValue == null) {
   ReturnValue = ApexPages.currentPage().getHeaders().get('X-Forwarded-For');
  } 
  Http h = new Http();
  HttpRequest req = new HttpRequest();
  req.setEndpoint('http://www.telize.com/geoip/'+ReturnValue);
  req.setMethod('GET');
  HttpResponse res;
  try{
   res = h.send(req);
   Map<String, Object> m = (Map<String, Object>)JSON.deserializeUntyped(res.getbody());
   country =(String)m.get('country');
   isp=(String)m.get('isp');
   ip=(String)m.get('ip');
   latitude=(Integer)m.get('latitude');
   longitude =(Integer)m.get('longitude');
   timezone =(String)m.get('timezone');
  }catch(Exception e){
  }
 }
}

Uniqueness in combination of two fields

In the account object Say we have to maintain uniqueness on 2 fields(name and phone).

we need to create a new Text field that has been set as unique.  This field can then be updated based on a workflow rule.


Create a workflow
In the Rule Criteria section in the first drop down menu choose "Account: phone" not equal to and then leave the value blank. Click the “Save & Next” button.


click the "Add Workflow Action" drop down and click "New Field Update". Give the name to update the field name. In the Field to update dropdown choose the Field created. In the "Specify New Field Value" section choose "Use a formula to set new value". Click the “Show Formula Editor” link. Click "Insert Field". Find the "External Field" field. Click the "Insert" button. Click the "Save" button. Click the "Done" button. Click the "Activate" button.



This Can be achieved even with trigger. Please find the below code

trigger updateaccountExternalField on Account (before insert, before update) {

    Map<String, Account> accountMap =new Map<String, Account>();
    for (Account acc : Trigger.new){
        if ((acc.phone  !=null) &&(Trigger.isInsert ||(acc.phone  != Trigger.oldMap.get(acc.Id).phone))){
            if (accountMap.containsKey(acc.Name+acc.phone)){
                acc.External_Field__c .addError('Another Account has the same phone.');
            }else{
                accountMap.put(acc.Name+acc.phone, acc);
            }
       }
    acc.External_Field__c = acc.Name+acc.phone;
    }
    
    for (Account account : [SELECT External_Field__c FROM Account WHERE External_Field__c IN :accountMap.KeySet()]){
        Account newContact = accountMap.get(acc.External_Field__c);
        newContact.External_Field__c.addError('An Account with this phone already exists.');
    }
}

Tuesday, August 18, 2015

Bulk Data load integration across two different organizations

I tried the code which was posted in salesforce blogs
https://developer.salesforce.com/blogs/developer-relations/2015/07/using-apex-to-integrate-salesforce.html
I made some minor changes to trigger and the class to bulk load data between two different organizations.

Create Trigger on account object.
trigger SendAccount on Account(after insert)
{
 String jsonstr = JSON.serializePretty(Trigger.new);
 SendAccountUsingRESTAPI.callcreateAcc(jsonstr);
}

SendAccountUsingRESTAPI Apex Class

public class SendAccountUsingRESTAPI {
  private final String clientId = 'Client Id From Connected App';
   private final String clientSecret = 'clientSecret From Connected App';
   private final String username = 'User Name';
   private final String password = 'Password';
  public class deserializeResponse
   {
      public String id;
      public String access_token;
   }
  public String ReturnAccessToken (SendAccountUsingRESTAPI acount)
   {
      String reqbody = 'grant_type=password&client_id='+clientId+'&client_secret='+clientSecret+'&username='+username+'&password='+password;
     Http h = new Http();
      HttpRequest req = new HttpRequest();
      req.setBody(reqbody);
      req.setMethod('POST');
      req.setEndpoint('https://login.salesforce.com/services/oauth2/token');
      HttpResponse res = h.send(req);
      System.debug('\n Body Response:'+res.getbody());
      deserializeResponse resp1 = (deserializeResponse)JSON.deserialize(res.getbody(),deserializeResponse.class);
      return resp1.access_token;
   }
   
   @future(callout=true)
   public static void callcreateAcc(String jsonstr)
   {
      SendAccountUsingRESTAPI acount1 = new SendAccountUsingRESTAPI();
      String accessToken;
      accessToken = acount1.ReturnAccessToken (acount1);

       if(accessToken != null){
          String endPoint = 'https://ap1.salesforce.com/services/apexrest/v1/sampledemo/';

           Http h2 = new Http();
           HttpRequest req1 = new HttpRequest();
           req1.setHeader('Authorization','Bearer ' + accessToken);
           req1.setHeader('Content-Type','application/json');
           req1.setHeader('accept','application/json');
           req1.setBody(jsonstr);
           req1.setMethod('POST');
           req1.setEndpoint(endPoint);
           HttpResponse res1 = h2.send(req1);
        
           String trimmedResponse = res1.getBody().unescapeCsv().remove('\\');
           
           List<Account> accountsDeserialized = (List<Account>) JSON.deserialize(trimmedResponse, List<Account>.class);
           List<Account> lstAccount=new List<Account>();
           for(Account acc:accountsDeserialized){
               Account ac=new Account(Id=acc.Customer_ID__c);
               ac.Customer_ID__c=acc.Id;
               lstAccount.add(ac);
           }
           
           if(!lstAccount.isEmpty()){
               update lstAccount;
           }
        }
   }
}
In the Other Salesforce Org we need to created a rest web service. I create a sampledemo class
@RestResource(urlMapping='/v1/sampledemo/*')
global with sharing class sampledemo {

    @HttpPost
    global static String createAccount(){
        String requestBody = RestContext.request.requestBody.toString();
       // List<Account> accountsDeserialized = (List<Account>) JSON.deserialize(requestBody, List<Account>.class);
        //insert accountsDeserialized;
        List<Account> accountsDeserialized=new List<Account>();
        List<Object> m = (List<Object>)JSON.deserializeUntyped(requestBody);
        for(Object obj:m){
            Map<String,Object> requests = (Map<String,Object>)obj;
            Account acc=new Account();
            acc.Name=(String)requests.get('Name');
            acc.Customer_Id__c=(Id)requests.get('Id');
            accountsDeserialized.add(acc);
        }
        
        if(!accountsDeserialized.isEmpty()){
            insert accountsDeserialized;
        }
  
        String returnResponse = JSON.serialize(accountsDeserialized);
        return returnResponse;
    }
}
I tried the below code to load 3 accounts. It made 2 callouts(one for authentication and the other for data sync).
List<Account> lstAccount=new List<Account>();
for(Integer i=0;i<3;i++){
 Account acc=new Account();
 acc.Name= 'Test Sample'+i;
 lstAccount.add(acc);
}
insert lstAccount;
The response we get from the External org will be in JSON format. The response we are parsing and updating the customer id field.

Friday, August 7, 2015

Resolution for Too many future calls limit in Apex

In Sales force we do have many limits one among them is @future calls(asynchronous). Salesforce has a limit of 50 future calls for a single transaction.

Salesforce has introducted Queueable interface supersede the old @future annotation in Apex. now you can chain a job to another job an unlimited number of times.

Trigger
trigger SendAccount on Account(after insert)
{ 
 for(Account a : Trigger.new)
  {
 SendAccountUsingRESTAPI.callcreateAcc(a.Name, a.Id);
  }
}
SendAccountUsingRESTAPI Apex Class
public class SendAccountUsingRESTAPI {
  @future(callout=true)
   public static void callcreateAcc (String accName, String accId)
   {
  System.debug('Created Account Name:'+accName);
  System.debug('Created Account Id:'+accId);
   }
}

I tried to call future method 50 times below is code. Execute the code in developer console or on the Apex Execute on Workebench

List<Account> lstAccount=new List<Account>();
for(Integer i=0;i<51;i++){
 Account acc=new Account();
 acc.Name= 'Test Sample'+i;
 lstAccount.add(acc);
}
insert lstAccount;
I modifed the trigger and created a new class AccountQueuebleJob which implements Queueable. I ran the same code above eeverything when fine.
trigger SendAccount on Account(after insert)
{
  List<Account> lstAccount =new List<Account>();
  for(Integer i=0;i<Trigger.new.size();i++){
      if(i<50){
          SendAccountUsingRESTAPI.callcreateAcc(Trigger.new[i].Name, Trigger.new[i].Id);
      }else{
          lstAccount.add(Trigger.new[i]);
      }
  }
  
  if(!lstAccount.isEmpty()){
      ID jobID = System.enqueueJob(new AccountQueuebleJob(lstAccount));
  }
}
AccountQueuebleJob Class
public class AccountQueuebleJob implements Queueable, Database.AllowsCallouts {

    private List<Account> lstAccount;
    
    public AccountQueuebleJob(List<Account> lsacc){
        this.lstAccount = lsacc;
    }

    public void execute(QueueableContext context) {
        if(!lstAccount.isEmpty()){
            for(Account a:lstAccount){
                SendAccountUsingRESTAPI.callcreateAcc(a.Name, a.Id);
            }
        }
        
    }
}

Thursday, August 6, 2015

Passing Objects/sObjects to Future Annotated Methods

Future Method 

The future annotation is a great feature on the Salesforce Platform to allow you to execute custom logic asynchronously. I often use them to perform callouts within the context of a database trigger.  However, one of the restrictions of future annotations is that you can not pass sObjects or objects as arguments to the annotated method. I regularly use encapsulation to pass a collection of parameters, or even an sObject, but this won’t work in @future method:

But thankfully there is a way you can do using JSON serialize|deserialize methods.
public with sharing class InsertAccountFuture {
 public static void createAccountUsingFuturer () {
  List<String> lstAccount = new List<String>();
  Account a1 = new Account('Sample Acount1');
  Account a2 = new Account('Sample Acount2');
  Account a3 = new Account('Sample Acount3');
  lstAccount.add(JSON.serialize(a3));
  lstAccount.add(JSON.serialize(a2));
  lstAccount.add(JSON.serialize(a3));
  createAccounts(lstAccount);
 }
 @future
 static void createAccount(List<String> lstAccount) {
  List<Account> insAccounts=new List<Account>();
  for (String ser : lstAccount)
  {
   insAccounts.add((Account) JSON.deserialize(ser, Account.class));
  }
  if(!insAccounts.isEmpty()){
   insert insAccounts;
  }
 }
}

Monday, August 3, 2015

Multiselect picklist in visualforce page


The Image Look like this.

In this demo we are displaying all contacts in the available contacts. Querying on the Contact object in the MultiselectController constructor.

Once after select some contact names and if you click on save button. you will get the id and the name of the respective record.



Visualforce Page

    
        
            
            
           
     
{!message}
Apex Component

  
  
  
  
  

  
  

  
    
Add Remove Up Down
Apex Class
public with sharing class MultiselectController {
    // SelectOption lists for public consumption
    public SelectOption[] leftOptions { get; set; }
    public SelectOption[] rightOptions { get; set; }
 
 public SelectOption[] selectedContacts { get; set; }
    public SelectOption[] allContacts { get; set; }
 
 public String message { get; set; }
 
 public MultiselectController() {
        selectedContacts = new List<SelectOption>();
        
        List<Contact> contacts = [SELECT Name, Id FROM Contact];    
        allContacts = new List<SelectOption>();
        for ( Contact c : contacts ) {
            allContacts.add(new SelectOption(c.Id, c.Name));
        }
    }
    
    // Parse &-separated values and labels from value and 
    // put them in option
    private void setOptions(SelectOption[] options, String value) {
        options.clear();
        String[] parts = value.split('&');
        for (Integer i=0; i<parts.size()/2; i++) {
            options.add(new SelectOption(EncodingUtil.urlDecode(parts[i*2], 'UTF-8'), 
              EncodingUtil.urlDecode(parts[(i*2)+1], 'UTF-8')));
        }
    }
    
    // Backing for hidden text field containing the options from the
    // left list
    public String leftOptionsHidden { get; set {
           leftOptionsHidden = value;
           setOptions(leftOptions, value);
        }
    }
    
    // Backing for hidden text field containing the options from the
    // right list
    public String rightOptionsHidden { get; set {
           rightOptionsHidden = value;
           setOptions(rightOptions, value);
        }
    }
 
 public PageReference save() {
        message = 'Selected Contacts: ';
        Boolean first = true;
        for ( SelectOption so : selectedContacts ) {
            if (!first) {
                message += ', ';
            }
            message += so.getLabel() + ' (' + so.getValue() + ')';
            first = false;
        }
        
        return null;       
    }
}

Wednesday, July 29, 2015

Resolution for too many DML rows in Apex when inserting/updating Error


This error is seen when a user performs DML operation on an entity(s) which contains more than 10000 records in a single transaction , i,e if a user executes upsert/update/insert operation on a collection object which contains more than 10000 records a user friendly error message "Error of Too many DML rows when a DML statement has been executed "is displayed.  This is governor limit error.

if you ran the Below code in the execute anonymous block or in the Work bench apex Execute 
List<Account> lstAccount=new List<Account>();
for(Integer i=0;i<10001;i++){
Account acc=new Account();
acc.Name= 'Test Sample'+i;
lstAccount.add(acc);
}
insert lstAccount;

Create a class and have a future method. Please find the code below
public class LoadBulkData{
    @future
    public static void loadData(List<String> lstAccountInfo){
        if(!lstAccountInfo.isEmpty() && lstAccountInfo.size() <= 10000)
        {
            List<Account> lstAccount=new List<Account>();
            for(String str:lstAccountInfo)
            {
                lstAccount.add((Account) JSON.deserialize(str, Account.class));
            }
            
            if(!lstAccount.isEmpty()){
                System.debug('Size In Account'+lstAccount.size());
                insert lstAccount;
            }
        }
    }
}
Execute the Below Code in develper console or Apex Execute on Work bench  
List<Account> lstAccount=new List<Account>();
for(Integer i=0;i<10001;i++){
Account acc=new Account();
acc.Name= 'Test Sample'+i;
lstAccount.add(acc);
}
if(lstAccount.size()>10000){
account[] mylist2 = new account[0];
account[] mylist3 = new account[0];
for(Integer j=0;j<lstAccount.size();j++){
 if(j== lstAccount.size()-1){
  mylist3.add(lstAccount[j]);
 }else{
  mylist2.add(lstAccount[j]);
 }
}
System.debug(mylist2.size());
System.debug(mylist3.size());

if(!mylist2.isEmpty()){
insert mylist2;
}
if(!mylist3.isEmpty()){
List<String> lstStringaccounts=new List<String>();
for(Account ac:mylist3)
lstStringaccounts.add(JSON.serialize(ac));
LoadBulkData.loadData(lstStringaccounts);
}
}
In order to resolve this issue, asynchronous method (@future annotation) needs to be used. Asynchronous methods increase the limits to 10,000, but do not scale with batch size (note there is also a limit for the number of asynchronous method invocations per transaction of 10). Please note, @future method runs only there is enough system resource available

Tuesday, July 28, 2015

How to use an iframe in Visualforce




Accessing documents of inactive user

The System Administrator has access to all Documents, except those that are stored within a user's Personal Documents Folder.  To obtain access to the inactive user's documents please do the following:


1. Reactivate the relevant inactive user.
2. Change their e-mail address to your own.
3. Reset their password.
4. Log in as the user and move the required Documents into another Public Document Folder.

You have uncommitted work pending. Please commit or rollback before calling out

You can't make callouts, HTTP or otherwise, once you have made changes to the database. It's true that you cannot make callouts with pending transactions in the request context.  Also, it's not possible to do an explicit commit.  So your only way out is to make the callout in a separate context.

You cannot perform a DML operation prior to a callout. All the DML operations should be invoked only after you are done with callouts.So, make a webservice callout first and then save the request.

If you are making multiple callouts, then save all the requests in a list or map and post callouts you save them.

Basically the following scenario will work :-

query
callout
query
callout
insert

callout
callout
callout
insert or update

But the following scenario will fail :-

callout
insert
callout  <---- fails="" here="" p="">
Possible workaround :-
-----------------------------------------------------------------------------------------

1) You either need to commit the transaction, make the callout prior to any database changes or move your callout to an @future method (place @future annotation to the webservice method).

2) Splits the transaction into two separate Ajax processes. The first inserts the record and the second performs the callout and is able to update the newly inserted record.

You can save the records and then respond to the user with a temporary page with a "Loading" message as you make the second call back to perform the callout.  To make it look seamless, you can also make successive  AJAX calls to save records and to make callout as user sees "Loading" message upon clicking "Save" button.

4) Sometimes customer do not want to place @future annotation to the webservice method as they need a response from the webservice to decide if they  have to rollback the insert or not ?

They can execute an action to insert the object and then execute the webservice callout on the oncomplete event of a commandButton. Then, return a PageReference giving the user immediate feedback.
If the webservice callout returns any error, then delete the object and returning the user back to the same page.

See below:

@VisualforcePage

 

@Controller
public PageReference save() {
 insert obj;
}
 
public PageReference executeWS(){
 obj = [SELECT ...];
 try{
  callout ws;
 } catch(System.Exception ex){
  delete obj;
  ApexPages.addMessages(e);
  return null;
 }
 return new PageReference('/' + id);
}

Disable or delete an Apex Class or Trigger from a Production Organization

Steps to Remove or Disable 


1. Force.com IDE should be installed.
2. Connect to the Sandbox Instance using the IDE and find the class or trigger that you want to delete.
3. Open the matching .xml file, and change the Status XML tag from Active to Deleted.
4. Or to disable the trigger change it to Inactive.
Note: Apex class Status can only be changed to "Active" or "Deleted," not "Inactive".
5. Save the file.
6. Select the two files (Code and XML) using "Ctrl-click," and then right-click on one of them.
7. Select Force.com | Deploy to server.
8. Provide your credentials for the Production org and follow the steps.

convert a 15 character id to a 18 character id in salesforce

1. Navigate to the  Custom Fields and Relationships of the Object:
Setup> Customize> Object> Fields> Custom Fields and Relationships> New

2. Select Formula as the Field Type

3. Name the Field and select Text as the Return Type

4. Input the following Formula into the Formula Editor:

CASESAFEID(Id)

5. Set Field Visibility, add/ remove from Pagelayout(s), and Save

use validation rules to prevent users from modifying closed won/lost Opportunities

Here are two approaches to preventing users from editing Closed or Closed Won opportunity records.  The examples below use example profile IDs in the formula syntax.  Note that the IDs used below will vary by organization.

** CLOSED **
The following Validation Rule will only allows users edit closed opportunities if they are assigned to a Profile ID listed (example is System Administrator "00et0000000q111" or Sales VP "00et0000000q222") will be able to edit the Opportunity.
Validation rule syntax:

AND(
PRIORVALUE( IsClosed ) = True,
NOT(OR(
$Profile.Id = "00et0000000q111",
$Profile.Id = "00et0000000q222"))
)


** CLOSED WON **
The following Validation Rule will only allows users edit closed/won opportunities if they are assigned to single profile ID below (example is System Administrator or "00et0000000q111") will be able to edit the Opportunity.

AND(
ISPICKVAL(PRIORVALUE(StageName),"Closed Won"),
NOT($Profile.Id = "00et0000000q111")
)


NOTES:
  • This rule will allow any user into the Edit mode, but will prevent Save, showing Validation Rule error message upon save
  • This rule will not allow a new "Add Product" on the Opportunity Line Items, you unless you are the Profile ID listed. For non System Admins, the Validation Rule will trigger on the "Save" page of the "Add Product" process
  • This rule will not prevent the "Edit" of existing Opportunity Line Items, for both System Admins and other Profile users
Other examples of useful validation rules can be found in the Help and Training here: Examples of Validation Rules

Monday, July 27, 2015

Salesforce integration across two different organizations

For this post, I will offer a simple explanation of the complex, yet interesting areas essential for the complete understanding of Salesforce Integration’s capabilities. The business scenario quoted, along with the working code samples, will be a good starting point for entering into the world of non-declarative ways for integrating with Salesforce. Here’s what I’ll cover:

Understanding authentication and its prerequisites
OAuth authentication flows for REST API calls
Apex triggers and callouts
REST API, REST web services, and Apex web services

1) Authentication and Its Prerequisites
Authenticating a client application is the first and foremost step while building an interface.

The authentication method depends on your chosen call type (REST or SOAP). Let’s see how to do it using REST.

Before moving any further, let’s frame a business scenario. We’ll use two Salesforce instances that exchange Account details. When a new Account is created in one org, it will flow down to the other Salesforce org, and in return the source org will get the Salesforce Record ID of the created record. These two orgs are:

Source Salesforce org (used for callout) – Source
Target Salesforce org (used for receiving requests) – Target

Following our business scenario, we can say that authentication is a collection of the following sub-steps. Though actual authentication calls a trigger from the Apex code, consider these steps as the prerequisites because without them being completed first, the authentication calls won’t work.

Choosing OAuth Endpoint (to be invoked from Source org)
Choosing OAuth Authentication flow (to be used by Source org)

Remote Site Setting in Source Org.

 Connected App enables Salesforce to recognize and authenticate an external application as a new entry point. OAuth is used for this authentication. We need to create a Connected App record in Target org. Below is an illustration.

Connected App in Target Org.
callback url should be specified in the remote site setting
Once after saving the record the client id and clientSecret are generated.

Create a Trigger to make an asynchronous call from source org to target org

Trigger on account Object:
trigger SendAccount on Account(after insert)
{
for(Account a : Trigger.new){
   SendAccountFromSource.createAccount(a.Name, a.Id);
}
}
Apex Class to make a callout :
Replace the clientid,secret,username and password's of your org.

public class SendAccountFromSource {
 private final String clientId = 'Clent Id from App';
 private final String clientSecret = 'clientSecretfrom app';
 private final String username = 'username';
 private final String password = 'passwordwithsecuritytoken';
 public class deserializeResponse
 {
  public String id;
  public String access_token;
 }
 public String ReturnAccessToken (SendAccountFromSource acount)
 {
  String reqbody = 'grant_type=password&client_id='+clientId+'&client_secret='+clientSecret+'&username='+username+'&password='+password;
  Http h = new Http();
  HttpRequest req = new HttpRequest();
  req.setBody(reqbody);
  req.setMethod('POST');
  req.setEndpoint('https://login.salesforce.com/services/oauth2/token');
  HttpResponse res = h.send(req);
  deserializeResponse resp1 = (deserializeResponse)JSON.deserialize(res.getbody(),deserializeResponse.class);
  return resp1.access_token;
 }
 @future(callout=true)
 public static void createAccount(String accName, String accId) 
 {
  SendAccountFromSource acount = new SendAccountFromSource();
  String accessToken = acount.ReturnAccessToken (acount);

  if(accessToken != null)
  {
   String endPoint = 'https://ap2.salesforce.com/services/data/v32.0/sobjects/Account/';
   String jsonstr = '{"Name" : "' + accName + '"}';
   Http h2 = new Http();
   HttpRequest req1 = new HttpRequest();
   req1.setHeader('Authorization','Bearer ' + accessToken);
   req1.setHeader('Content-Type','application/json');
   req1.setHeader('accept','application/json');
   req1.setBody(jsonstr);
   req1.setMethod('POST');
   req1.setEndpoint(endPoint);
   HttpResponse res1 = h2.send(req1);

   deserializeResponse resp2 = (deserializeResponse)JSON.deserialize(res1.getbody(),deserializeResponse.class);
   Account a = [SELECT Id FROM Account WHERE Id = :accId];
   a.externalId__c = resp2.id;
   update a;
  }
 }
}

Explanation –
1 Setting the REST API resource to create an Account (sObject)
2 Creating the JSON string to be sent as the input
3 Setting the Header to include the access token
4 Querying the Account record in Source Org so it can be updated
5 Setting the custom foreign key field on Account in Source Org with the extracted Account ID from the response

Till here we have worked with rest api.

When working with rest webservices we need to change the code in the createAccount method in SendAccountFromSource class . Which looks like
if(accessToken != null)
{
 String endPoint = 'https://ap2.salesforce.com/services/apexrest/v1/createAccount/';
 String jsonstr = '{"AccName" : "' + accName + '"}';

 Http h2 = new Http();
 HttpRequest req1 = new HttpRequest();
 req1.setHeader('Authorization','Bearer ' + accessToken);
 req1.setHeader('Content-Type','application/json');
 req1.setHeader('accept','application/json');
 req1.setBody(jsonstr);
 req1.setMethod('POST');
 req1.setEndpoint(endPoint);
 HttpResponse res1 = h2.send(req1);

 String trimmedResponse = res1.getBody().unescapeCsv().remove('\\');
 deserializeResponse resp2 = (deserializeResponse)JSON.deserialize(trimmedResponse, deserializeResponse.class);
 Account a = [SELECT Id FROM Account WHERE Id = :accId];
 a.externalId__c= resp2.id;
 update a;
}

Here in this example we need to change the endpoint url that is pointing to createAccount class in the target org. Create a new rest web service class createAccount in target org.
@RestResource(urlMapping='/v1/createAccount/*')
global with sharing class createAccount 
{
 @HttpPost
 global static String createAccount(String AccName)
 {
  Account a = new Account();
  a.Name = AccName;
  insert a;
  String returnResponse = JSON.serialize(a);
  return returnResponse;
 }
}

Explanation –
1 Exposing the web service using the @RestResource annotation
2 Exposing method as REST resource to be called when HTTP Post request is made to this web service
3 Creating a new Account in Target org and setting the name as passed from Source org
4 Serializing the response (Account details) before sending
5 Sending the response.

Apex Web Service

Finally, the third option is the Apex Web Service that uses SOAP to handle integration. The class written at the target needs to be exposed as a global Web Service.
global class CreateAccountApexWS 
{
 global class sAccount
 {
  webservice String name;
 }
 webservice static String createAccount(sAccount sAcct)
 {
  Account acct = new Account();
  acct.Name = sAcct.name;
  insert acct;
  String returnResponse = JSON.serialize(acct);
  return returnResponse;
 }
}

Explanation –
1 Creating a Global class that can be accessed from anywhere
2 Using the webservice keyword to expose class variable as an input to the web service
3 Using the webservice keyword to expose the class method as a custom SOAP Web Service

Monday, April 27, 2015

How to access custom settings via JavaScript or Visual force page markup?

<apex:page >
<script type="text/javascript">
var url = "{!$Setup.MyCustomSet__c.URL__c}";
alert(url);
</script>
<apex:outputText value="{!$Setup.MyCustomSet__c.URL__c}"/>
</apex:page>

Thursday, February 19, 2015

deploy code from Sandbox to Production?

To deploy code from a Sandbox or Developer Edition org to Production, you will need to use either the Force.com Migration Tool or the Force.com IDE.
Note: If you deploy to a production organization, 75% of your Apex scripts must be covered by unit tests, and all of those tests must complete successfully.
While only 75% of your Apex code must be covered by tests, your focus shouldn't be on the percentage of code that is covered. Instead, you should make sure that every use case of your application is covered, including positive and negative cases, as well as bulk and single record. This should lead to 75% or more of your code being covered by unit tests.
Force.com Migration Tool
The Force.com Migration Tool is a Java/Ant-based command-line utility for moving metadata between a local directory and a Force.com organization.
- http://wiki.developerforce.com/index.php/Force.com_Migration_Tool
Force.com IDE
The Force.com IDE is a powerful client application for creating, modifying and deploying Force.com applications. Based on the Eclipse platform, it provides a comfortable environment for programmers familiar with integrated development environments, allowing you to code, compile, test, package and deploy all from within the IDE itself. Much of the actual work, such as compilation, happens on the Force.com platform—the Force.com IDE performs the communication and result parsing transparently.
- http://wiki.developerforce.com/index.php/An_Introduction_to_Force_IDE

Please refer to the Apex Language Reference Documentation for more information
http://www.salesforce.com/us/developer/docs/apexcode/salesforce_apex_language_reference.pdf
See the chapter on Deploying Apex Scripts

Apex Triggers throw the error SELF_REFERENCE_FROM_TRIGGER

You cannot recursively update or delete the same object from an Apex trigger.
This error often occurs when:

        * You try to update or delete an object from within its before trigger.
        * You try to delete an object from within its after trigger.   

This error occurs with both direct and indirect operations. The following is an example of an indirect operation:

       1. A request is submitted to update Object A.
       2. A before update trigger on object A creates an object B.
       3. Object A is updated.
       4. An after insert trigger on object B queries object A and updates it. This is an indirect update of object A because of the before trigger of object A, so an error is generated.

Tuesday, February 3, 2015

Creating a CSV file from salesforce and sending through the Email

List<Account> lstAccount = [Select id,Name,CreatedDate from Account limit 10];
string header = 'Id, Name , Created Date \n';
string finalstr = header ;
for(Account acc: lstAccount)
{
       string recordString = '"'+acc.id+'","'+acc.Name+'","'+acc.CreatedDate+'"\n';
       finalstr = finalstr +recordString;
}

Messaging.EmailFileAttachment sendCsv = new Messaging.EmailFileAttachment();
blob csvBlob = Blob.valueOf(finalstr);
string fileName= 'Accounts.csv';
sendCsv.setFileName(fileName);
sendCsv.setBody(csvBlob);
Messaging.SingleEmailMessage email =new Messaging.SingleEmailMessage();
String[] toAddresses = new list<string> {'test@gmail.com'};
email.setSubject('Accounts');
email.setToAddresses( toAddresses );
email.setPlainTextBody('Accounts');
email.setFileAttachments(new Messaging.EmailFileAttachment[]{sendCsv});
Messaging.SendEmailResult [] r = Messaging.sendEmail(new Messaging.SingleEmailMessage[] {email});

Tuesday, January 27, 2015

Get the updated field Name in trigger

Trigger updateAccount on Account(after update){
 for(Account act:trigger.new){
  Account oldAccountId=Trigger.oldMap.get(act.Id);
  Map<String, Schema.SObjectField> M = Schema.SObjectType.Account.fields.getMap();
  for (String str : M.keyset()) {
   if(act.str != oldAccountId.str){
    system.debug('******The value has changed!!!! ');
    // here goes more code
   }
  }
 }
}

Sending Emails Through Silverpop

Prerequiste:
Need to get the Web Portal Registration List Id from silver pop

Execute the below code to send an email

String xmlBody='<?xml version="1.0" encoding="UTF-8"?><Envelope><Body><AddRecipient><LIST_ID>Web Portal Registration List Id </LIST_ID><CREATED_FROM>2</CREATED_FROM><UPDATE_IF_FOUND>true</UPDATE_IF_FOUND><SEND_AUTOREPLY>true</SEND_AUTOREPLY><ALLOW_HTML>false</ALLOW_HTML><COLUMN><NAME>EMAIL</NAME><VALUE>xxxxx@gmail.com</VALUE></COLUMN><COLUMN><NAME>GUID</NAME><VALUE>d8a4ba8c-6fd0-acdb-1953-1726d797cb57</VALUE></COLUMN><COLUMN><NAME>FIRSTNAME</NAME><VALUE>xxx</VALUE></COLUMN><COLUMN><NAME>LASTNAME</NAME><VALUE>aaa</VALUE></COLUMN></AddRecipient></Body></Envelope>';

Http httpObj = new Http();
HttpRequest httpReq = new HttpRequest();       
httpReq.setEndpoint('http://api2.silverpop.com/XMLAPI');
httpReq.setMethod('POST');
httpReq.setHeader('Content-Type', 'text/xml;charset=utf-8');
httpReq.setBody(xmlBody);
HttpResponse httpResp = new HttpResponse();
try {
 httpResp = httpObj.send(httpReq);
 System.debug('Email Sent successfully');
} catch(Exception e) {
 System.debug('MEssage' + e.getMessage());
 System.debug('sendEmail : ' + e.getStackTraceString());
}

Wednesday, January 7, 2015

reference old or prior field value in apex trigger

To reference the old value of a field in a trigger, use the following syntax: 

Trigger.oldMap.get(account.Id).fieldName 

So to ensure a field was changed during an update trigger you will have: 

if (Trigger.isUpdate) { 
if (account.fieldname != Trigger.oldMap.get(account.Id).fieldName) { 
// Field has been changed! 
} 
} 

Labels

visualforce page ( 13 ) apex integration ( 5 ) apex trigger ( 4 ) csv file from vf page ( 4 ) javascript ( 4 ) csv visualforce page ( 3 ) Too many ( 2 ) call out ( 2 ) integration ( 2 ) rest api ( 2 ) salesforce rest api ( 2 ) salesforce to salesforce integration ( 2 ) sfdc rest api ( 2 ) trigger ( 2 ) 15 digit to 18 digit ( 1 ) DML rows in Apex ( 1 ) Date Conversion ( 1 ) Date/Time conversion ( 1 ) Deploy ( 1 ) Objects to Future Annotated Methods ( 1 ) SFDC limits ( 1 ) Sobject to Future Annotated Methods ( 1 ) Test Class ( 1 ) TimeZone Conversion ( 1 ) Too many dml rows ( 1 ) Too many future calls ( 1 ) annotations ( 1 ) apex code ( 1 ) closed opportunities ( 1 ) commit ( 1 ) convert ( 1 ) create records ( 1 ) csv create records ( 1 ) custom setting ( 1 ) deployment ( 1 ) deployment changeset ( 1 ) disable apex class ( 1 ) disable apex trigger ( 1 ) disable in production ( 1 ) document ( 1 ) download ( 1 ) field name ( 1 ) formula fields ( 1 ) iframe ( 1 ) inactive ( 1 ) intellisense ( 1 ) jsforce ( 1 ) limits ( 1 ) matrix report in vf page ( 1 ) multi select ( 1 ) multi select salesforce ( 1 ) multiselect ( 1 ) paypal ( 1 ) picklist ( 1 ) record type ( 1 ) rollback ( 1 ) salesforce limits ( 1 ) salesforce list ( 1 ) salesforce map ( 1 ) salesforce rest ( 1 ) salesforce set ( 1 ) salesforce1 ( 1 ) sandbox deployment ( 1 ) sfdc collection ( 1 ) sfdc list ( 1 ) sfdc map ( 1 ) sfdc rest ( 1 ) sfdc set ( 1 ) uncommitted ( 1 ) updated field ( 1 ) user ( 1 ) validation rule opportunity ( 1 ) validation rules opportunities ( 1 ) vf page ( 1 )

Ad