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

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