Tuesday, May 31, 2016

Setup MavensMate for salesforce - Windows 10

Recently I got a chance to setup MavensMate at windows 10 machine for salesforce. I tried but there were couple of issues which I faced. Just sharing the blog post to get rid of those issues & setup MavensMate on Windows 10 Machine.


#1-Install Sublime text 3 from below link –





#2-Click on the red marked link.
#3-Download & install this, restart sublime text after it is installed.
#5-Copy red marked text

#6-Open console in sublime text. You can find this option at View à Show Console.
#7-Paste this long text in console & hit enter.
#8-If it is failed try one more time. Once this is done restart sublime text.
#9-Go to preferences à package control
Type install MavensMate & hit enter
#10-Restart Sublime text 
#11-Create a folder in your directory for workspace.
For Eg – D:\ Mavensmate_Workspace

#12-open sublime text, go to MavensMate à Setting à User
You will see a node – “mm_workspace", put your workspace path here.

#13-To create a new project, go to MavensMate à New Project
#14-It will open url in Edge browser. This may show you below error, when you enter the login detail & try to create project.


#15-To resolve this issue, copy url (which is in Edge) & open firefox & paste it here, hit enter. Put all the login details & create project from here.

#16-You may see another error after this, error would be [XXX] - Access is denied.
To resolve this go to your workspace folder, right click, go to security & give all permissions to current user & all other user as well & then try to create.
This will solve your issue & will create a new project!!

Update - 11 Sept 2016
----------------------------------------------------------------------------------------
Result: [ERROR]: Request to the local MavensMate server failed. please ensure the MavensMate-app is installer and running.

In version 7+ of MavensMate for Sublime Text, there is a new companion app called MavensMate-app. You must download, install, and run this application in order for the MavensMate for Sublime Text plugin to operate. For more information, please visit https://github.com/joeferraro/MavensMate-app


Go to download section & download the exe according to OS.

install this, & whenever you want to run sublime text + mavensmate, you need to run this app first. after installation go to search & click on Mavensmate app first & then open sublime text. 




Thursday, July 9, 2015

As a beginner MAC OS user with Salesfoce

I am a window user & shifted on MAC recently, this move was not easy & come up with several issues. Struggling phase with MAC is still going on because when you start using MAC you realize that you don't know even simplest thing too :) a bit frustrating!


Couple of issued while setting up Eclipse + Force.com IDE for MAC OS, just sharing experience so you can save your time if you face this kind of issues.

1-In my eclipse I did not see autocomplete after foce.com ide installation, tried various tricks from internet but nothing works, after a lot of wasting time I came to know that I should install version 30 to see autocomplete feature, probably this is not available in latest releases.

Here is how you can do it- I am assuming you are already have an idea of below link
Foce.com IDE

When you add a "Foce.com IDE" & click on add there is a checkbox "Show Only latest Version Of Available Software", you need to uncheck it.
You will see couple of versions for Force.com IDE. You should select version 30 & after that install it.You will see autocomplete after this installation.


2-The other issue, which I was facing, is
 "An internal error occurred during: "Computing size". The profile is currently in use." 

After wasting a lot of time I came to know that, error is due to I am trying to install eclipse + Force.com Ide on FAT 32 partition. & Due to that it is not installing "Force.com IDE".
I moved it on MAC drive (Mac OS Extended (Journaled)) & that starts working.

3.I was trying to install the data loader on MAC but many people said dataloader is not build for MAC, it is build for windows only, after wasting some time, I got the version for MAC.

You can go to your salesforce org Setup >> Data Management >> Data Loader >> Download for MAC

4.I also tried if data loader command line tool can work on MAC, but still struggling with this. Probably it is not for MAC, OR it will take some time if any trick can work. But for now it is not working.

Also noticed that if you are using command line in windows & using latest version that will not work, you need to download version 30 for this & that will work.
You can download older version from this link.
http://www.cloudsuccess.com/resource-centre/apex-data-loader-archive/

5. As a beginner in MAC I noticed that I see Question mark for some app's. This one is not related to salesforce ☺.
When I click on them it will show a popup with that app & application folder. I don't understand it why it is doing like this even I have installed app.
At other hand when I am trying to removing some dmg file from hard drive it is showing a message that it can not be deleted.

Solution is very simple for this issue:-
a-when it shows a popup, you need to move that app in application folder, this is what it is trying to tell user by showing that popup but as a beginner it is not easy to understand.

b- When I did this, I could delete those dmg files too. To check from where app is working go to dock right click on app & click show in finder, it will show the place from where app is running.

c-All apps should run from application folder, so first move app in application folder & then drag & drop that app in dock. Right click on this icon & select "Keep this in doc" & that's it.

Thursday, April 30, 2015

A Web Service CallOut Per Minute In Between Business Hours

There was a very specific requirement from customer, as per the requirement he wanted to call a external websrvice in every minute during the business hours. I tried several ways to do it but that was really not simple. Even I was not sure it can hit any governor limit. I did google a lot for this but there was no help in case of per minute. Finally started to get if there is any solution in salesforce for this, without having confidence is this really possible in salesforce. But finally I got the solution & the best thing is it works without hitting any kind of governor limits. Here is the solution which can help if you stuck this kind of requirement.

#1-Create a new object called “Scheduled_Job__c”. This object will have below fields –
Request_DateTime__c – Type DateTime
Response__c – Type Long Text Area(32768)

This object will be used in two ways latter-
#A-track the request time &
#B-What is the response from the external web service.
#2-I created a batch class which allows callouts.
global class ScheduleLeads implements Schedulable,Database.AllowsCallouts {
 global void execute(SchedulableContext ctx) { 
      init(); 
 }
}

#3-Created a method in this class called ScheduleJob which will basically can be called from execute anonymous to schedule this job.
public static void ScheduleJob(){
 boolean isNeedToSchedule = true;
 String strSchedule = '';
/*here notice that we are adding a minute in current time, means it will be scheduled for next minute, you can change it even if you want to call every n minutes*/
 DateTime dt = Datetime.now().addMinutes(1);
/*Let’s say business hours is from 10 AM to 8 PM*/
 if(dt.hour() >=19 && dt.minute() >= 59){ 
         isNeedToSchedule = false;
 }else{
     strSchedule = '0 ' + dt.minute() + ' ' + dt.hour() + ' ' + dt.day() + ' ' + dt.month() + ' ?' + ' ' + dt.year(); 
     isNeedToSchedule = true;
 }
 if(isNeedToSchedule){
   String cronid = System.schedule('CalloutService_' + Datetime.now().getTime(), strSchedule, new ScheduleVWLeads());
  
   List listOfScheduledJob = [Select Id,Response__c from Scheduled_Job__c Order by CreatedDate DESC LIMIT 1];
   if(listOfScheduledJob != NULL && !listOfScheduledJob.isEmpty()){
    /*try{ 
     delete listOfScheduledJob;
    }catch(Exception ex){
     system.debug('exqqq::--->>>>' + ex);
    }*/
   }
   Scheduled_Job__c objScheduledJob = new Scheduled_Job__c();
   objScheduledJob.Name = cronid;
   objScheduledJob.Request_DateTime__c = datetime.now();
   insert objScheduledJob;
 }      
}

#4-Create another method called init
@future(callout=true)
  public static void init(){
     HttpRequest req = new HttpRequest();
  Http http = new Http(); 
  req.setMethod('GET');
  String requrl = 'YOUR_WEBSERVICE_URL'+ '?type=' + XYZ;
  req.setEndPoint(requrl);
  HTTPResponse res;
  if(!Test.isRunningTest()){
   Blob headerValue = Blob.valueOf('YOUR_WEBSERVICE_USERID' +':' +'YOUR_WEBSERVICE_PASSWORD');
   String authorizationHeader = 'Basic ' + EncodingUtil.base64Encode(headerValue);
   req.setHeader('Authorization', authorizationHeader);
   req.setTimeout(120000);
   res = http.send(req);
  }else{
   res = new HttpResponse();
   res.setHeader('Content-Type', 'application/json');
   res.setBody('DUMMY_RESPONSE_IN_CASE_OF_TEST_EXECUTES');
   res.setStatusCode(200);
   res.setStatus('Ok');
  } 
  String resBody;
  if(res != NULL){
   resBody = res.getBody();
   JSONParser parser = JSON.createParser(resBody);
   while (parser.nextToken() != null) {
    /*PROCESS YOUR RESPONSE HEREE */
   }
   ScheduleJob();
  }
  
 }

Here one important point is we are calling the schedulejob method in init again so this is scheduled for next minute.
Now if you start this job at some particular time daily let’s say when business start 10 AM in morning, go to schedule job & schedule a job by using this class. That’s it. The job will start on regular time daily & in code we are having a condition when it will stop. So in this way the job will execute from 10 AM to 8 PM daily.
You can either keep ScheduleJob records for tracking or can delete if not needed. In the above code there is a piece of code which is commented & that is deleting the ScheduleJob object records.

Happy ending! :)

Avoid simultaneous update/ Control same record if already opened by someone in edit mode & show a message to end user

Recently I came across a requirement where client wanted to track if any other user also open the same record to edit, in this case he wanted to show a message to second user so he can edit the same record latter.

To solve this I created a custom setting let’s say Control_Record_Edit__c. Created few other fields to track edit mode –

Name
Edit_DateTime__c
User_Id__c

Name:- field will save record id which is opened in edit mode by someone.
Edit_DateTime__c:- field will tell us how long someone open a record in edit mode
User_Id__c:- field will tell us who open that record in edit mode.


Now let’s say we want to track lead record. We will create a new VF page that will be called LeadEdit.page. In this page we will have a function called init which will basically insert a record in our custom setting, so next time whenever someone open the same lead it edit mode we can check in code & show a message that another user is already opened this lead in edit mode.

<apex:page standardController="lead" extensions="LeadEditController" action="{!init}">
 <apex:form id="form1">
  <apex:outputPanel rendered="{!isNeedToShowMsg}">
   <apex:pageMessages id="error"/>
   <apex:commandButton value="Go To Lead" action="/{!objLead.Id}" style="margin-left: 20px;"/>
  </apex:outputPanel>
 </apex:form>  
</apex:page>


Class code is as below
public with sharing class LeadEditController {
 public Lead objLead {get;set;} 
 public boolean isNeedToShowMsg {get;set;}
 public LeadEditController(ApexPages.StandardController stdController){
  objLead = (Lead)stdController.getRecord();
 }
  
 public PageReference init(){
  isNeedToShowMsg = false;
  PageReference pr = NULL;
  List listOfControlLeadUpdate = [SELECT Id,User_Id__c,Edit_DateTime__c from Control_Lead_Update__c where Name=:objLead.Id and User_Id__c !=:Userinfo.getUserId() LIMIT 1];
  if(listOfControlLeadUpdate != NULL && !listOfControlLeadUpdate.isEmpty()){
   List listOfUser = [Select Id, Name from User where Id=:listOfControlLeadUpdate.get(0).User_Id__c LIMIT 1];
   if(listOfUser != NULL && !listOfUser.isEmpty()){
    String Msg = 'Another User ' + listOfUser.get(0).Name + ' already start editing the same lead at '+  listOfControlLeadUpdate.get(0).Edit_DateTime__c.format()  +', Please wait for sometime & click on edit button again!'; 
    ApexPages.Message apexmsg = new ApexPages.Message(ApexPages.Severity.INFO, Msg);
             ApexPages.addMessage(apexmsg);
             isNeedToShowMsg = true;
   } 
   
  }else{
   Control_Lead_Update__c objControlLead = new Control_Lead_Update__c();
   objControlLead.Name = objLead.Id;
   objControlLead.Edit_DateTime__c = datetime.now();
   objControlLead.User_Id__c = Userinfo.getUserId();
   try{
    insert objControlLead;
   }catch(Exception ex){
    system.debug('exception::-->>>' + ex);
   }
   pr = new PageReference('/' + objLead.Id + '/e?nooverride=1&retURL=/apex/LeadCancel?Id=' + objLead.Id);
  } 
  return pr; 
 }
 
 public PageReference initCancel(){
  LeadHandler.ReleaseEditModeForOthers(new List{objLead});
  PageReference pr = new PageReference('/' + objLead.Id);
  return pr;
 }
}



Here after this one other issue appear when user click on cancel, if user open a lead & click on cancel we should remove his record from custom setting but the problem is cancel override is not available in salesforce. To handle this we created another page that is called LeadCancel & we are passing it in the retURL parameter.

<apex:page standardController="lead" extensions="LeadEditController" action="{!initCancel}">

</apex:page>

now in the class code there is a method initCancel, that is basically deleting the record from custom setting if a user open a lead & click on cancel button. also we are passing this cancel page in retuURL parameter so when user click on cancel it will be back to our page.

There is only one point here which is important, if a user open a lead & close it by browser close button then we can not track that action & in that case no one can edit the same lead until that record does not removed from custom setting.

Tuesday, August 12, 2014

Small Utilities Method


Hi friends, I am back from long time, in between this I could not get a chance to post anything new.
In this post I am showing you small utility methods which we use everyday. This can help if you are looking any quick tip or help -
Map mapOfUserRole = new Map([SELECT Id, Name, ParentRoleId FROM UserRole]);
Map mapOfUserRoleWithHierarchy = new Map();

public void processRoles(){
  String level = '';
  List ListOfUserRole = [SELECT Name, Id FROM UserRole];
  if(ListOfUserRole != NULL && ListOfUserRole.Size()>0){
   for(UserRole u:ListOfUserRole){
    level = processParentRole(u.Id,'');
    if(level != ''){
     mapOfUserRoleWithHierarchy.put(u.Id,level);
     
    }
   }
  }
 }
 
public String processParentRole(Id role, String hierarchyString){
  UserRole userrole = mapOfUserRole.get(role);
  if(userrole.ParentRoleId != NULL){
   hierarchyString += '>>' + userrole.Name;
   return  processParentRole(userrole.ParentRoleId,hierarchyString);  
  }else{
   hierarchyString += '>>'+userrole.Name;
   return hierarchyString;
  }
 }
 
processRoles();
here if you debug mapOfUserRoleWithHierarchy map you will see something like below -
00EXXXXXXXX=>>Team1>>Team2>>Team3>>Team4>>CEO
here I am assuming that hierarchy in your system something like
    -CEO
       -Team4
          -Team3
             -Team2
                -Team1     
Hope this can help if you are doing some code & need something related to user role hierarchy! will keep adding other util method in this post so this can be used kind of quick reference:)

Wednesday, August 7, 2013

How to give a name while export a file in csv/xls

Hi friends, recently I came across a situation where client want's to give a name while exporting a file in csv/xls. In salesforce we can not code in such a way that it will ask you any name before save the file at your local drive. Alternate solution is we can pass different names from the different pages, so we can distinguish in between two exported files from different pages. Here is the detail how you can do this.

We need to create below resources for it-

#1-BlogCSV.page
#2-BlogCSV.component
#3-BlogCSVController.cls
#4-ExportTestPage.page


let me take this one by one & tell you how we can pass name while export in this.

#1-BlogCSV.page 
This is a VF page which generate a xls file for given table.
here the important thing is we will pass contenttype attribute something like below





contentType="application/vnd.ms-excel#{!SUBSTITUTE($CurrentPage.parameters.page,'XXXXXX__','')}_YOUR_POSTFIX_HERE.xls"

in this the exported file name will be build by Page Name from where it is exported + your postfix whatever you give in above content type attribute.

here is the complete code for this-
<apex:page language="en-US" cache="false" readonly="true" sidebar="false" showHeader="false" pageStyle="false" contentType="application/vnd.ms-excel#{!SUBSTITUTE($CurrentPage.parameters.page,'PackagePrefix__','')}_YOUR_POSTFIX_HERE.xls">
  <c:BlogCSV id="csvComponent1" />
</apex:page>


#2-BlogCSV.component 
this component is simply rendering the account table which will be going to export.
<apex:component controller="BlogCSVController" id="component1">
 <apex:pageBlock >
        <apex:pageBlockTable value="{!lstOfAccount}" var="lst" width="100%" rendered="{!IF(lstOfAccount.Size>0,true,false)}">
         <apex:column >
                  <apex:facet name="header" >
                    Name
                  </apex:facet>
                  <apex:outputLink value="{!lst.id}" >{!lst.Name}</apex:outputLink>  
              </apex:column>
              <apex:column >
                  <apex:facet name="header" > 
                     AccountSource
                  </apex:facet>
                  <apex:outputLabel value="{!lst.AccountSource}" />  
              </apex:column>
        </apex:pageBlockTable>
    </apex:pageBlock>    
</apex:component>

#3-BlogCSVController.cls
this class is common controller class for both component & page. here is the code for this -
public with sharing class BlogCSVController {
 public string currentPage {get;set;} 
 public String redirectURL {get;set;}
  public PageReference Export(){
     
     
     PageReference pr = Page.BlogCSV;
     pr.getParameters().put('page',currentPage);
     redirectURL = pr.getUrl(); 
     return null; 
    }
    
 public List lstOfAccount{get;set;}
 public BlogCSVController(){
  lstOfAccount = [Select Id,Name, AccountSource from Account LIMIT 10];
 }
}

#4-ExportTestPage.page
finally this is the page where will provide export button which will initiate export.Here is the code-
<apex:page controller="BlogCSVController">
 <apex:form id="form1">
  <apex:pageMessages id="msg" />
  <apex:sectionHeader Title="Export" subtitle="XLS Sample" /> 
  <apex:pageBlock id="block1">
   <apex:pageBlockButtons location="top">
    <input type="button" class="btn" value="Export" onclick="Export('{!$CurrentPage.Name}');" />
                  <apex:actionStatus id="statusLoadingMain">
                      <apex:facet name="start">
                              <span style="font-weight:bold; color: red;">
                                  Please wait while exporting...<img src="/img/loading.gif" /> 
                              </span> 
                      </apex:facet>
                  </apex:actionStatus>
              </apex:pageBlockButtons>
   
   <script>
     function Export(pagename){
             jsExport(pagename);
          } 
   </script>
    
    <apex:outputPanel id="pnlExport"> 
             <script>
                 if("{!redirectURL}" != ""){
                     window.location.href="{!redirectURL}";
                 }
             </script>
         </apex:outputPanel>
         <apex:actionFunction status="statusLoadingMain" name="jsExport" action="{!Export}" rerender="pnlExport,msg">
                     <apex:param name="currentPage" id="currentPage" value="" assignto="{!currentPage}" />
                   </apex:actionFunction>
   </apex:pageBlock>     
   <c:BlogCSV id="csvComponent1" />    
 </apex:form>          
</apex:page>

here notice that we are passing current page name in action function.
Now when you click on export this will be exported with your page name & given postfix.
You can see a demo here