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

Thursday, January 30, 2020

After Update Trigger In Salesforce Apex

Trigger Scenario:

Lets take a sample use case when an Opportunity stage has been changed to Closed-Won ,I want to create a new Invoice(custom object) record with below data mapping.
  • Invoice Opportunity - Same Opportunity where Stage has been modified.
  • Invoice Account - Account Related To This Opportunity.
  • Invoice Total Quantity - The sum the quantity of all opportunity line items(opportunity products) related to the same Opportunity.


The relationship between all these objects as below




Source Code:


trigger OpportunityTrigger on Opportunity (after update)
{
    if(Trigger.isAfter && Trigger.isUpdate)
 {
  OpportunityTriggerHandler.opportunityAfterUpdate(Trigger.new,Trigger.oldMap)
 }
}


Public Class OpportunityTriggerHandler
{
  public static void opportunityAfterUpdate(List<Opportunity> TriggerNew,Map<Id,Opportunity> TriggerOldMap)
  {
   Set<id> setOppIds = new Set<id>();
   Map<Id,Decimal> mapOppIdtoSumOfLineitems = new Map<Id,Decimal>();
   for(Opportunity opty:TriggerNew)
   {
    if('Closed Won'.equalsIgnoreCase(opty.StageName) && opty.StageName!=TriggerOldMap.get(opty.Id).StageName)
    {
     setOppIds.add(opty.id);
    }
   }
   
   if(!setOppIds.isEmpty())
   {
    List<Invoice__c> listInvocesToInsert = new List<Invoice__c>();
    for(Aggregateresult agr:[SELECT sum(quantity) qunty,Opportunityid FROM Opportunitylineitem WHERE Opportunityid IN:setOppIds GROUP BY Opportunityid])
    {
                mapOppIdtoSumOfLineitems.put((id)agr.get('Opportunityid'),(decimal)agr.get('qunty'));
    }
    
    for(Opportunity op:TriggerNew)
    {
     if('Closed Won'.equalsIgnoreCase(op.StageName) && op.StageName!=TriggerOldMap.get(op.Id).StageName && mapOppIdtoSumOfLineitems.containsKey(op.id)
     {
      Invoice__c inv = new Invoice__c();
      inv.name = 'Trigger-'+op.Name;
      inv.ParentAccount__c=op.Accountid;
      inv.ParentOpportunity__c=op.id;
      inv.Discount__c=mapOppIdtoSumOfLineitems.get(op.id);
      listInvocesToInsert.add(inv);
     }
   }
   if(!listInvocesToInsert.isEmpty())
    Database.insert(listInvocesToInsert,false);
   }
  }
}

Please comment or write us if you have any queries/requirements.

Please like,follow,bookmark,subscribe this site to receive daily updates.



Hope this helps you..Enjoy..!




Sunday, January 26, 2020

Custom Permissions Are Not Working In Apex

Lets assume you have created a custom permission and it's assigned to user through permission sets.

Now when your referring the same value in apex for the assigned user it's still giving a false instead of the true value .

This could be happening because of the  Session Activation Required setting is enabled on the permission set level.

Please disable this and try it out probably it should work.





Please comment or write us if you have any queries/requirements.

Please like,follow,bookmark,subscribe this site to receive daily updates.




Hope this helps you..Enjoy..!

How To Access Custom Permission in Apex

  • Let's assume you have created a custom permission and it's been assigned to permission set or profiles.
  • Now we can refer the same custom permission in apex to check whether it's enabled for logged in user or not.
  • We use will the checkPermission() method from the FeatureManagement class for the same.

Boolean enabSet = System.FeatureManagement.checkPermission('Custom Permission APi Name');
System.debug('enabSet..'+enabSet);

Example:
Boolean enabSet = System.FeatureManagement.checkPermission('SreeTest');
System.debug('enabSet..'+enabSet);

Please comment or write us if you have any queries/requirements.

Please like,follow,bookmark,subscribe this site to receive daily updates.



Hope this helps you..Enjoy..!

Wednesday, January 8, 2020

How To Populate A Map With List or Set (Where Collections As a Value) in Salesforce

As a developer most of the times we will be working on collections.One of the most common used collection in salesforce is maps.

Creating a simple maps(value as a string,integer,object etc..) is very easy
  • Map<String,String>
  • Map<String,Integer>
  • Map<key,objects>
The real picture comes into scenario when we want to build some complex maps(where value of a map it self again a collection like list,set etc) 
  • Map<String,list<Account>>
  • Map<integer,set<integer>>
  • Map<AccountId,list<Conatct>>
Most common mistakes that we do while building this complex maps are
  • Old value gets overrides by new values.
  • When your in loop you map always ends up with just holding the last record in list/set.
  • Didn't checking whether value is already is exist or not.
Scenario:

Let take a take I want to create a map which will takes case status as key and it's value is all the cases comes under the same status.

Map<String,List<Case>> mapStatusToCases = new Map<String,List<Case>>()

for( Case cs: [SELECT id,Status,CaseNumber FROM Case limit 20])
{
 //Check whether with same status any record is already is added to map or not
 
 if(mapStatusToCases.containsKey(cs.Status)) 
 {
    // If you directly put this case into the map it will overrides all the existing cases,
   // which is not correct.So get all the existing records and store it list/set.
  List<Case> existingCase = mapStatusToCases.get(cs.Status);
  //add this new record to existing list  
  existingCase.add(cs);
  // now put the same status into the map with all latest case records(existing+new),
  // because key is same so it will overrides existing values with this latest list
  mapStatusToCases.put(cs.Status,existingCase); 
 }
 
 else // this executes if the status is not there in map(it means coming first time)
 {
     //prepare variable of map value type
  List<case> lstNewCases = new List<Case>();
  // adding a new record
  lstNewCases.add(cs); 
  // add the new status as a key and case as a value into map
  mapStatusToCases.put(cs.Status,lstNewCases); 
 }
}

System.debug('All Key Set...'+mapStatusToCases.keySet());
System.debug('All Values in Map...'+mapStatusToCases.values());
System.debug('Complete Map Details...'+mapStatusToCases);

For better understanding in above I have written each statement in a separate line. The same code can also be written in an optimized way as shown below.Both are valid and same.


Map<String,List<Case>> mapStatusToCases = new Map<String,List<Case>>()

for( Case cs: [SELECT id,Status,CaseNumber FROM Case limit 20])
{
 //Check whether with same status any record is already is added to map or not
 
 if(mapStatusToCases.containsKey(cs.Status)) 
 {
  //this statement mapStatusToCases.get(cs.Status) will returns the list
  //So,I'm adding new record to existing list directly
  mapStatusToCases.get(cs.Status).add(cs); 
 }
 
 else // this executes if the status is not there in map(it means coming first time)
 {
     //Delcared a new list and directly adding a new record to that
  mapStatusToCases.put(cs.Status,new List<Case>{cs}); 
 }
}

System.debug('All Key Set...'+mapStatusToCases.keySet());
System.debug('All Values in Map...'+mapStatusToCases.values());
System.debug('Complete Map Details...'+mapStatusToCases);

OutPut:




Please watch this space more useful stuff.

Please follow,bookmark,subscribe this site to receive daily updates.

Facebook - https://www.facebook.com/ILoveCodingYou/?ref=bookmarks


Hope this helps you..Enjoy..!







Wednesday, January 1, 2020

Few Scheduled Jobs Got Stopped Working Suddenly in Salesforce

If you have figured out that some of your scheduled jobs got stopped working suddenly.. There could be same issue which we have run into and figure out eventually after some time..

As the year got changed, while scheduling the jobs initially if you have mentioned a year as 2019 or till 2019 in your cron string expression then all your scheduled jobs comes under this category would have been stopped since Jan 1st 2020 at 12:00Am.

There could be some other reasons which might cause the issue but this is the one of route cause we have to cross as year got changed. 

Wish you a happy new year to everyone...



Tuesday, December 31, 2019

How To Build A Global Search URL In Lightning Experience Using Apex

If your in lightning experience on click of any actionable item you want to take the user to the Global Search and perform the search action using the dynamic search string.To get the url of the global search in lightning using apex please refer the below code.


String searchStr = 'Sree'; //Search String
String stringToEncode = '{"componentDef":"forceSearch:search","attributes":{"term":"'+searchStr+ '","scopeMap":{"type":"TOP_RESULTS"},"context":{"disableSpellCorrection":false,"SEARCH_ACTIVITY":{"term":"'+ searchStr + '"}}}}';
String encodedStr = EncodingUtil.base64Encode(Blob.valueOf(stringToEncode)); //Base64 encoding
String redirectUrl='/one/one.app?source=aloha#'+encodedStr;

The format of url must be

     String redUrl = '/one/one.app?source=aloha#'+base64EncodedSearchString;

If you want to the same thing using java script please refer this post


Hope this helps you..Enjoy..!




Sunday, December 29, 2019

Continuation Integration In Salesforce

Problem: 

When multiple agents are using same visual force page (User Interface) and we are making an external call out to fetch the data from the back end systems,if the external service is taking more time (more than 5 sec) to respond ,all such transactions will be treated as a long running transactions in salesforce .At at any given point of time salesforce allows only 5 long running processes in system and it automatically terminates the other requests and it will not allow the agents to perform any other actions.

New Approach: 

Our salesforce system is more dependent on other services to provide the necessary data to the agent usually we will end up with same issue many times.So,we have decided to change the existing integration model and for all new integrations we have started using continuation frame work.In this frame work all the external call outs which are taking longer time ,all these long running requests will be converted into asynchronous callout and this will not be counted under the salesforce limits and also it will not stop the agents doing other works.

Usually agent can request for data on click of any button or action in visual force and this will make an external call out (step 1) and the app server will handover the request to continuation server before it returning to the visual force page  (steps 2–3) .The Continuation server sends the request to the Web service and receives the response (steps 4–7), then hands the response back to the app server (step 8). Finally, the response is returned to the Visual force page (step 9).



Hope this helps you..Enjoy..!

Saturday, December 28, 2019

What is Salesforce API Portal?

This is the new feature of Salesforce which will help us to find all api details to connect with any of their platforms/entire ecosystem through apis.

We can also say it's one place store to check out all salesforce api details.

This will also shows what is the sample request and response details for each and every api.

It will also helps the developers to learn with an interactive document.

This helps the developer to connect with entire eco system.

This is built on Mulesoft API Community Manager.

Sample API/Clouds:

  • B2C Commerce Developer Sandbox API's
  • Einstein Prediction Service Scoring API
  • Einstein Vision and Einstein Language
  • Marketing Cloud REST API

For more details please check Salesforce Official Documentation.

Hope this helps you..Enjoy..!



Monday, December 16, 2019

System.JSONException: Apex Type unsupported in JSON: Object

You will receive this error when your parsing/deserialize  the JSON responses either user the JSON classes or JSON Parser classes.Please read the below points
  • When you deserialize the response into specified class type and if that class is having any field with data type "Object" you will receive this error.
  • When you any JSONToApex Converter or JSONToC# we will end up with this issue.
  • Please replace all the fields with Object data type into String/Integer etc..
Sample JSON:


{
  "item": [
    {
      "CONTRACT": 1001117406,
      "SOLD_TO": 10081120,
      "PURCH_NO_C":,
      "STREET": "1290 Hamner Ave",
      "STR_SUPPL1": "",
      "STR_SUPPL2":,     
    }
  ]
}

After Coverting JSONToApex:

public class Item
{
    public integer CONTRACT { get; set; }
    public integer SOLD_TO { get; set; }
    public object PURCH_NO_C { get; set; }
    public string STREET { get; set; }
    public string STR_SUPPL1 { get; set; }
    public object STR_SUPPL2 { get; set; }
}

public class RootObject
{
    public List<Item> item { get; set; }
}



Deserialize the JSON:

JSONParser parser = JSON.createParser('sampleJsonResponse');
 RootObject pr= (RootObject)parser.readValueAs(RootObject.class); 
//Here you will receive an error because the RootObject.class is having fields (PURCH_NO_C,STR_SUPPL2)  of type Object .

WorkAround:
Please change the wrapper class fields data type from Object to appropriate types as integer,double,string etc

public class Item
{
    public integer CONTRACT { get; set; }
    public integer SOLD_TO { get; set; }
    public string PURCH_NO_C { get; set; }
    public string STREET { get; set; }
    public string STR_SUPPL1 { get; set; }
    public string STR_SUPPL2 { get; set; }
}

public class RootObject
{
    public List<Item> item { get; set; }
}

Hope this helps you..Enjoy..!


Continuation Method is Not Getting Called In Salesforce APEX

Please check the below points

  • Check whether this class is linked with any visual force page/lightning components,if it's not linked to any one of this then it will not executed.

  • If it's in visual force page please check whether your adding reRender attribute on the <apex:commandButton> or <apex:outputlink> tag where your invoking the Continuation.

Hope this helps you..Enjoy..!

Thursday, December 5, 2019

System.LimitException: Too many DML statements: 1

Exception:

If you use below code it will throw an error System.LimitException: Too many DML statements: 1 if you have any dml statement in your aura-method.






public with sharing class GetAllAccountsCntrl {
   @AuraEnabled(cacheable=true)
    public static List<Account> processAllAccounts() 
 {
        List<Account> lstAcc = new List<Account>();
  for(Account acc:[SELECT Id, Name,AccountSource,Website, Createddate FROM Account Limit 10])
  {
      acc.Name = 'LWC Testing...';
   lstAcc.add(acc);
  }
  Database.update(lstAcc,false);
  return lstAcc;
    }

}

Workaround:

Please remove (cacheable=true) from your method declared above,then this will work without any error



public with sharing class GetAllAccountsCntrl {
   @AuraEnabled
    public static List<Account> processAllAccounts() 
 {
        List<Account> lstAcc = new List<Account>();
  for(Account acc:[SELECT Id, Name,AccountSource,Website, Createddate FROM Account Limit 10])
  {
      acc.Name = 'LWC Testing...';
   lstAcc.add(acc);
  }
  Database.update(lstAcc,false);
  return lstAcc;
    }

}


Hope this helps you..Enjoy..!

How To Throw An Exception From Apex (Server Side) To JavaScript(Client Side) Controller in LWC

In lightning if you want to throw something as error from Apex class to client side Js controller ,we can use the salesforce standard class AuraHandledException.

Please look at the below code snippet where I'm trying to call an api to get the weather information,basis on the api response you can throw an exception(received in valid status,received process status but didn't got the expected response etc..) wherever you want throw an exception to the client side controller.

If your using try and catch in your code and if you raise an exception in try it will automatically goes to catch block and from there it will return to client side controller.


global class WeatherReportCntrl
{

@AuraEnabled(cacheable=true)
public static string fetchWeatherReport()
{
   Http http = new Http();
   HttpResponse res = new HttpResponse();
   HttpRequest req = new HttpRequest();
   req.setEndpoint('endpoint');
   req.setMethod('GET');
   try
    {
 res = http.send(req);                      
 string responseValue =res.getBody();
 if(res.getStatus()=='OK' && res.getStatusCode()==200 && String.isNotBlank(responseValue)
 {
    //while processing some error came then
    System.debug('responseValue--->'+responseValue);
    if(someerror)
     throw new AuraHandledException('Error while Processing data');  

   return 'data processed successfully';
 }
 else
       {
 // Received some invalid status code
  throw new AuraHandledException('Received some invalid status');
 
 }
    }
   Catch(Exception e)
   {
       AuraHandledException ex = new AuraHandledException(String.valueOf(e));
       ex.setMessage('Exception caught in catch block');
       throw ex;
   }
 } 
}


Hope this helps you..Enjoy..!

Friday, August 23, 2019

Creating a Salesforce Scratch Org Using SFDX CLI

sfdc force:org:create -a <yourScartchOrgAliasName> -d 30 -f config/project-scratch-def.json -s

If you want to create a scratch org using the Salesforce CLI please use the below the command.

sfdx force:org:create -a <aliasNameOfYourOrg> -d <duration 1-30> - f <file path> -s (defaults)

sfdc force:org:create -a <aliasNameOfYourOrg> -d 30 -f config/project-scratch-def.json -s

-d   -- Scratch org duration 1 to 30 days
-a   -- Alias name that you give for your scratch org
-s    -- defaults this org for all ongoing commands
-f    -- config file location



You can specify all your scratch org configuration in this config file before you run this command


Hope this helped you..Enjoy..!


Basic Structure Of SFDX CLI Commands

Basically all the CLI commands will be in below format

namespace:topic:[Subtopics]:methodName

namespace             --  force/lightning
topic                       -- apex/org/data
Subtopics               -- apex:class,data:bulk,auth:web
methodname          -- final action

Sample Commands:

force:alias:list
force:alias:set
force:apex:class:create
force:apex:execute
force:apex:log:get
force:apex:log:list
force:apex:log:tail
force:apex:test:report
force:apex:test:run
force:apex:trigger:create
force:auth:jwt:grant
force:auth:list
force:auth:logout
force:auth:sfdxurl:store
force:auth:web:login
force:config:get
force:config:list
force:config:set
force:data:bulk:delete
force:data:bulk:status
force:data:bulk:upsert
force:data:record:create
force:data:record:delete
force:data:record:get
force:data:record:update
force:data:soql:query
force:data:tree:export
force:data:tree:import
force:doc:commands:display
force:doc:commands:list
force:lightning:app:create
force:lightning:component:create
force:lightning:event:create
force:lightning:interface:create
force:lightning:lint
force:lightning:test:create
force:lightning:test:install
force:lightning:test:run
force:limits:api:display
force:mdapi:convert
force:mdapi:deploy
force:mdapi:deploy:cancel
force:mdapi:deploy:report
force:mdapi:describemetadata
force:mdapi:listmetadata
force:mdapi:retrieve
force:mdapi:retrieve:report
force:org:clone
force:org:create
force:org:delete
force:org:display
force:org:list
force:org:open
force:org:shape:create
force:org:shape:delete
force:org:shape:list
force:org:snapshot:create
force:org:snapshot:delete
force:org:snapshot:get
force:org:snapshot:list
force:org:status
force:package1:version:create
force:package1:version:create:get
force:package1:version:display
force:package1:version:list
force:package:create
force:package:hammertest:list
force:package:hammertest:report
force:package:hammertest:run
force:package:install
force:package:install:report
force:package:installed:list
force:package:list
force:package:uninstall
force:package:uninstall:report
force:package:update
force:package:version:create
force:package:version:create:list
force:package:version:create:report
force:package:version:list
force:package:version:promote
force:package:version:report
force:package:version:update
force:project:create
force:project:upgrade
force:schema:sobject:describe
force:schema:sobject:list
force:source:convert
force:source:delete
force:source:deploy
force:source:deploy:cancel
force:source:deploy:report
force:source:open
force:source:pull
force:source:push
force:source:retrieve
force:source:status
force:user:create
force:user:display
force:user:list
force:user:password:generate
force:user:permset:assign
force:visualforce:component:create
force:visualforce:page:create


Hope this helped you..Enjoy..!

Saturday, July 6, 2019

Base Lightning Components in Salesforce LWC

In Lightning web components(lwc) we will Base Lightning Components to display the particular record information/to create a record quickly with provided information with out using any custom apex.

List of the available Base Lightning Components are
  • lightning-record-edit-form
  • lightning-record-form
  • lightning-record-view-form

lightning-record-edit-form:

  • This component wrapper accepts the record id to display one or more fields and labels related to that field corresponding to given record id 
  • This will not require any apex because it uses Lightning Data Services to fetch the data
  • This will not support Standard objects like Task and Events.
  • Use lightning-output-field to display data in read only format
  • Use lightning-input-field to edit these fields in edit on record edit page

lightning-record-form:

  • Use this component to build the forms quickly to create a record,view the record or to update the record. 
  • Building the record creation forms is easier than building the form using lightning-record-edit-form and lightning-record-view-form. 
  • This component accepts 4 properties like object name which is mandatory,record id which is optional in case of create record ,mode to specify view/edit/read only and layout type like Full or compact
  • It will also takes care of FLS and sharing rules
 <lightning-record-form  
   record-id="739hchjsh773"  
   object-api-name="Position__c"  
   layout-type="Full"  
   mode="view">  
 </lightning-record-form>  

lightning-record-view-form:

  • Use this component when you want to dispaly the record on view mode
  • This will not require any apex because it uses Lightning Data Services to fetch the data
  • This will not support Standard objects like Task and Events.
  • It will also takes care of FLS and sharing rules.

For more information refer:

Hope this helps you...Enjoy!