Thursday, 18 November 2021

Map contains key is case sensitive

 Here is my previous post related to map contains method. 

How contains key method works ? Does it allow partial matches or exact matches ?

We know map contains key method is case sensitive. if you are create a key using First Name , Last Name and DOB to find unique Account record then system will consider 2 different record for below scenario.

1. First Name - "Capital"  Last Name- "Testing" DOB- 01/01/1989

2. First Name - "CAPITAL" Last Name - "TESTING" DOB- 01/01/1989

The work wound is 

map<String,Account> map_Name_Acc = new map<String,Account>();

String sKey = '';

for(Account acc:[SELECT firstname,Lastname,DOB__c from Account limit 10]{

    sKey = acc.FirstName+'_'+ acc.LastName+'_'+acc.DOB__c; // this will create duplicate records since key is case sensitive

 sKey = acc.FirstName.toLowercase()+'_'+ acc.LastName.toLowercase()+'_'+acc.DOB__c; 

}

toLowercase() - convert name to lower case, "CAPITAL" and "Capital" will be "capital"

Friday, 5 November 2021

How to split String from the character '*' ?

 This is a bug in split function, it does not work for '*'  or '+'.  We will get runtime error.

System.StringException: Invalid regex: Dangling meta character '*' near index 0 * 

String sBody = '*   Building Name:Brookwood Gardens  *   Is your unit isolated with barrier systems in place?Yes  *   Does your unit have its own supplies?Yes  *   Does your unit have any additional infection control equipment?HVAC filters: YesUVC lights: Yes';

List<String> strList = sBody.split('*'); // This will throw error.

system.debug('strList '+strList);

Solutions: List<String> strList =sBody.split('\\*'); // This will solve.

 

Thursday, 28 October 2021

How to Identify whether Logged User has particular custom permission assigned ?

Earlier days we used to use Custom Permission in Visualforce page and Formula fields etc.

We used to assign custom permission to a permission set. and We used to have one utility method to check whether user has permission set or not.

public static Boolean doPermissoncheck(String sPermissionName, String sUserId){
    Boolean isPermAssigned;
    List<PermissionSetAssignment> lstOfAssignment 
    = [SELECT IdPermissionSet.Name,AssigneeId FROM PermissionSetAssignment
      WHERE PermissionSet.Name =:sPermissionName AND AssigneeId=:sUserId];
    isPermAssigned = lstOfAssignment.isEmpty()?false:true;
    return isPermAssigned;
        
}

What If we want to know custom permission from one Permission Set ?
public static Boolean isThisCustomPermissionAssigned(String customPermissionName, 
PermissionSet myPermissionSet){
     CustomPermission customPermission = 
     [SELECT Id FROM CustomPermission WHERE DeveloperName = :customPermissionName Limit 1];
     List<SetupEntityAccess> isPermissionSetAssigned = 
     [SELECT Id FROM SetupEntityAccess WHERE ParentId = :myPermissionSet.Id 
     AND SetupEntityId = :customPermission.Id];
     return !isPermissionSetAssigned.isEmpty();
 }
The key here is the object SetupEntityAccess which act as middle object to connect to
Permission set and Custom Permission, It also act same way when we add
custom permission to Profile.

To add/remove a custom permission from a permission set:
public static void addRemoveCustomPermission(Boolean addNewPermission, 
String sPermissionSetName,String sCustomPermissionName){

    List<PermissionSetLstPermissionSet = 
    [SELECT Id FROM PermissionSet WHERE Label = :sPermissionSetName];
    List<CustomPermission> lstcustomPermission = 
    [SELECT Id FROM CustomPermission WHERE DeveloperName = :sCustomPermissionName];

    if(addNewPermission){
        SetupEntityAccess enablePermission = new SetupEntityAccess
(ParentId=LstPermissionSet[0].IdSetupEntityId=lstcustomPermission[0].Id);
        insert enablePermission;
    }
    else{
        List<SetupEntityAccess> permissionToRemove = [SELECT Id 
FROM SetupEntityAccess 
WHERE ParentId = :LstPermissionSet[0].Id 
AND SetupEntityId = :lstcustomPermission[0].Id];
        delete permissionToRemove[0];
    }
    
}

Now we don't need all these codes to check If user has custom permission assigned or not.
Just one line of code will suffice.
Boolean hasCustomPermission =
FeatureManagement.checkPermission('customPermissionSetname');

https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_class_System_FeatureManagement.htm

Friday, 22 October 2021

Apex programming Tricks

Convert List to Map 

Lets assume we have list of accounts record and we need to create map of Id to Account record.

Traditional  approach is using Iterating over list of Account records and storing in a Map. but the easiest approach is 

List<Account> lstofAccount = [Select id,name from Account limit 10];
system.debug('lstofAccount--'+lstofAccount);
Map<Id,Account> map_account = new Map<Id,Account>(lstofAccount);
system.debug('map_account--'+map_account);
11:00:02:011 USER_DEBUG [4]|DEBUG|
map_account--{00111000029360TAAQ=Account:{Id=00111000029360TAAQ
Name=Area Agency on Aging Region 9RecordTypeId=012360000005HcsAAE}, 
00111000029360UAAQ=Account:{Id=00111000029360UAAQName=AULTMAN HOSPITAL
RecordTypeId=012360000005HcsAAE}}

Remove Duplicate Elements from List or Convert List to Set

Most of the time, we may require only unique values from List, the easiest ways is add those value in a set , set will automatically remove duplicate values. How to add list of values to a set without having to iterate 

List<String> lstSFDCTerms = new List<String>
{'Aura','LWC','Lightning','SDLS','Aura','LWC','VF','APEX','JS'};
system.debug('lstSFDCTerms size--'+lstSFDCTerms.size());
Set<String> setOfSFDCTerms =  new Set<String>(lstSFDCTerms);
// we can also do setOfSFDCTerms.addAll(lstSFDCTerms);
system.debug('setOfSFDCTerms size--'+setOfSFDCTerms.size()+'--setOfSFDCTerms--'
+setOfSFDCTerms);

11:21:54:002 USER_DEBUG [2]|DEBUG|lstSFDCTerms size--9

11:21:54:002 USER_DEBUG [4]|DEBUG|

setOfSFDCTerms size--7--setOfSFDCTerms--{APEXAuraJSLWCLightningSDLSVF

How to Use Switch case on String ?

Sometime we may need to check if set contains one particular value then execute particular action. If we have more condition then switch care is better approach as compared to If-else.

Use case - We need to get role Id based on responsibility selected by users. You may have 500 roles defined in your org. What is the best approach ?

for(String sres :responsibility){
   switch on sres {
      when 'Guardian' {
         sRoleId = map_RoleId_Resp.get('Guardian');
         break;
      }
      when 'Legal Guardian Responsible' {
        sRoleId = map_RoleId_Resp.get('Legal Guardian Responsible');
        break;
      }
      when 'Power of Attorney/Healthcare' {
        sRoleId = map_RoleId_Resp.get('Power of Attorney/Healthcare');
        break;
      }
      when 'Durable Power of Attorney/Healthcare' {
        sRoleId = map_RoleId_Resp.get('Durable Power of Attorney/Healthcare');
        break;
      }
      when 'Power of Attorney/Financial' {
        sRoleId = map_RoleId_Resp.get('Power of Attorney/Financial');
        break;
      }
      when 'Durable Power of Attorney/Financial' {
       sRoleId = map_RoleId_Resp.get('Durable Power of Attorney/Financial');
       break;
      }
      when 'Other Legal Oversight' {
       sRoleId = map_RoleId_Resp.get('Other Legal Oversight');
       break;
      }
            
      when else{
          sRoleId = map_RoleId_Resp.get('Portal User');
                break;
      }
}



Wednesday, 20 October 2021

How to get record-Id in LWC screen action ?

 If you have created quick action and referred LWC component, you will get "Undefined" as Record Id in ConnectedCallback method, This is the issue I have come across. 

connectedCallback() {
        console.log('connected===============');
        console.log(this.recordId); // This will print undefined.
}

Solutions - 1: We can wrap LWC component with aura, and pass record Id.
<aura:component implements="force:lightningQuickActionWithoutHeader,
force:hasRecordId,force:appHostable>
   <c:updateFiles recordId="{!v.recordId}"/>
</aura:component>

Solution - 2 Use RecordId in component html code.
<div style="display:none">
    {recordId}
 </div>

Component Controller
import { LightningElement,api,track } from 'lwc';
import { CloseActionScreenEvent } from 'lightning/actions';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
export default class UpdateFiles extends LightningElement {
    @api recordId;
   
    connectedCallback() {
        console.log('connected===============');
        console.log(this.recordId);
        
    }
}

Component Code
<template>
    <lightning-quick-action-panel header="Mark Files To Be Deleted">
        <div style="display:none">
            {recordId}
        </div>
        <div slot="footer" class="slds-modal__footer">
     <lightning-button variant="destructive" label="Cancel"></lightning-button>
  <lightning-button class="slds-m-left_x-small" variant="brand" 
label="Delete Files"  onclick={getSelectedRec>
</lightning-button>
            
          </div>
    </lightning-quick-action-panel>
</template>

XML code
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>52.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
  <target>lightning__RecordAction</target>
</targets>
<targetConfigs>
  <targetConfig targets="lightning__RecordAction">
    <actionType>ScreenAction</actionType>
  </targetConfig>
</targetConfigs>
</LightningComponentBundle>


Tuesday, 28 September 2021

How to display formatted value in LWC component ?

1. Hide all numbers and display only 4 digits of SSN or credit card.

Declare a variable in Java Script controller that is being used in LWC component.

<lightning-formatted-number value={ssn}></lightning-formatted-number> 

 In the java script controller 

var num = '123456789234'; // you are getting SSN from apex class

ssn = num.slice(-4).padStart(num.length,'*');

Console.log('ssn',ssn);



2. Append . to the end of string.

var charString = 'Learning Salesforce';

charString.padEnd(30,'.');


3. Append Currency Symbol 

var testNum = 123445.34;

testNum.toLocaleString('en-IN',{style:"currency",currency:'INR'});

testNum.toLocaleString('en-US', { style: 'currency',currency:'USD'})

testNum.toLocaleString('de-DE', { style: 'currency', currency: 'EUR' })

testNum.toLocaleString('en-GB', { style: 'currency', currency: 'EUR' })


4. Display percentage value

var testNum = 0.2;

testNum.toLocaleString('en-US', { style: 'percent'})





Thursday, 23 September 2021

How to create Chatter Post and Notification from Flow ?


 It is very easy to create chatter post using process builder, there are many cool articles there.

https://automationchampion.com/2015/10/03/getting-started-with-process-builder-part-47-mention-a-related-user-in-a-post-to-chatter-action/

This post is in regards to create notification and chatter post using flow.

Use Case :We have downstream system which needs opportunity data from salesforce, we have fire and forgot integration approach to integrate both systems. Now on successful response we need to notify users that Opportunity has been pushed and one Id has been created in Downstream system.

Chatter Post 

1. Create Record Triggered Flow and Add your entry condition

2. Add action element

3. Select Messaging and Action as Post to Chatter

4. Create Text Template Type variable and Add your chatter message, 

Even you can tag chatter post to certain users. Sometimes we can see <P><B> in the message, please remove that tag when we view message in text format in Field.

Hi @[{!$Record.OwnerId}] Resident {!$Record.Name} has been pushed .@[{!$Record.Liaison__c}] @[{!UserRec.Id}]

5. Populate Message value as Text Template variable 

6. Populate Target Name or Id as Opportunity Record Id, so that chatter post will be added as feed item to record.

Chatter Post - 



Custom Notification

1. Define custom notification Type

2. Add Getrecords to get Notification Type Id


3. Add Action element. Select Notifications and Action as "Send Custom Notification"

4. Populate fields 

Custom Notification Type ID - Populate record Id got from step 2 Get records

Notification Body - Create Constant Field and text

Notification Title - "Matrix Update"

Recipient IDs - Collection Variable add all user Id, or chatter group Ids 

Target Id - opportunity Record id





Here is total flow 


When user log in to salesforce, they will see one unread message in the bell icon



Please let me know by adding comments how this is helpful for your use case.





Thursday, 16 September 2021

How to have Chaining Promises in Lighting Component ?

We may need to call multiple apex function from aura component, each function is dependent to other function. In that case we may have call promise function inside another.

Here is the sample code

@AuraEnabled
public static Opportunity getOpportunity(String opptyId){
        return [select id,name,stagename from Opportunity where id='opptyId']
 }

@AuraEnabled
public static Boolean checkFormAttached(String opptyId){
        Boolean isNotAttached = true;
        set<String> setOfNames = new set<String>
{'Admission Notification','EligibilitySummary','BAForm'};
        List<ContentDocumentLink> contLinks = [SELECT id,contentdocument.Title,
LinkedEntityId FROM ContentDocumentLink 
                                               WHERE LinkedEntityId =:opptyId 
                                               AND contentdocument.Title IN:setOfNames];
        return contLinks.size()>0;
 }

Java script controller
({ doInit : function(component, event, helper){
        
        let checkAttachment = helper.checkAttachment(component, event, helper, false);
        
checkAttachment.then(function(result){
            // if result is true then call function
            if(result){
                
                let getoppy = helper.getopportunity(component, event, helper, false);
                  
                getoppy.then((globalResults) => {
                }).catch((error) => {
                     
                let toast = {title: "Error", type: "error", message: "An error occurred while searching for matching residents."}; helper.showToast(toast); component.set("v.closeModal", true); return;
});
}
});
}
})

Helper class
({
checkAttachment : function(component, event, helper){
        console.log('checkAttachment called');
         let opptyId = component.get("v.recordId");
         console.log('opptyId ',opptyId);
        //check attachments
    let checkAttachments = helper.executeAction(component, "c.checkFormAttached", {"opptyId":opptyId});
return checkAttachments.then((results) =>{
             console.log('results 39',results);
             if(!results){
              helper.showToast({type: "error",
title: "Attachment Missing",
message: "Please attach at least one of the following – Admission Notification, BA Form, Eligibility Summary"});
component.set("v.closeModal", true);
component.set("v.isLoading", false);
return false;
            }else{
                console.log('results 46',results);
                return true;
            }
         });
        
    },
executeAction: function(component, actionName, params) { return new Promise(function(resolve, reject) { var action = component.get(actionName); action.setParams(params); action.setCallback(this, function(response) { if (component.isValid() && response.getState() === 'SUCCESS') { resolve(response.getReturnValue()); } else { reject(response.getError()[0]); } }); $A.enqueueAction(action); }); },
getResidents : function(component, event, helper){
         let getoppy= helper.executeAction(component, "c.getOpportunity", {"opptyId":opptyId});
return
getoppy.then((results) => {
            if(results){
                return results;
}else{return null;}
});
}
})

Wednesday, 15 September 2021

How to float text in lightning web component ?

 Use Case - Publish message to all users in salesforce in Home Page or any other record page.

                   1. It should be easily configurable.

                   2. We can stop displaying message whenever we want from a configuration. It should have Start Time and End Time.

Here is my approach to achieve the same.

1. Create a custom Object Salesforce_News__c. custom fields - Start_Date__c , End_Date__c, Active__c and Message__c



2. Create record page for  Salesforce_News__c and add the page to application. 

3. Create a permission set "Salesforce News configure"  which will have Create,Edit access to object Salesforce_News__c.

4. Assign permission to user who is going to configure message.

5. Create LWC component 

6. Add LWC component to Home Page.

Here is LWC component code.

<template>
<marquee> 
<div class="slds-clearfix" if:true={showMessage}>
  <div class="slds-float_left">
    <p>
    <b><span style="color:red">Important Note : </span>
    <span style="color:white;font-family: Arial, Helvetica, sans-serif;
 font-size: medium;">{newsTicket.Message__c}
    </span></b>
    </p>
  </div>
</div>
</marquee>
</template>

Javascript
import { LightningElement,api } from 'lwc';
import showMessage from '@salesforce/apex/NewsTickerCls.showMessage';
export default class NewsTicker extends LightningElement {
    showMessage;
     @api newsTicket;
     connectedCallback(){
         this.showMessage = false;
         showMessage()
         .then(res => {
             if(res !=null){
                  this.showMessage = true;
                  this.newsTicket = res;
                  console.log('this.newsTicket--',this.newsTicket);
             }
            
             
         });
         
     }
     
}

XML code
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>52.0</apiVersion>
    <isExposed>true</isExposed>
     <targets>
        <target>lightning__RecordPage</target>
        <target>lightning__AppPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

Apex class
public with sharing class NewsTickerCls { @AuraEnabled public static Salesforce_News__c showMessage(){ Datetime currTime = System.now(); List<Salesforce_News__c> currentMessag = [Select Message__c
from Salesforce_News__c
where Active__c = true AND start__c <:currTime AND End__c >: currTime limit 1]; If(!currentMessag.isEmpty()){ return currentMessag[0]; } return null; } }
Test class
@isTest
private class NewsTickerClsTest {

   @isTest  
    static void dotest(){
        Salesforce_News__c news = new Salesforce_News__c();
        news.Message__c = 'Test Message';
        news.start__c = System.today()-1;
        news.End__c = System.today()+1;
        news.Active__c = true;
        Insert news;
        test.startTest();
        Salesforce_News__c result = NewsTickerCls.showMessage();
        System.assert(result !=null);
        test.stopTest();
            
    }
}



Tuesday, 14 September 2021

How to get Salesforce lookup field object id using javascript ?

 When we  add a look input field then salesforce add a hidden field to capture Id. We need to get value from hidden field to get record Id.

For example 

<apex:inputfield value="{!Custom__c.lookField__c}"  id="lookupfieldId" />

<script type="text/javascript">

function getLookupId()

{

var fieldId = document.getElementById('{!$Component.lookupfieldId}_lkid').value;

alert('id'+fieldId );

}

</script>

We can also inspect field to get Id use it 

var fieldId =  document.getElementById('{!$Component.pageId:formId:pgBlkId:pgBlkSecId1:lookupfieldId}_lkid').value;

Monday, 13 September 2021

How to change aura component bundle version ?

Source org and target org should be in compatible version to have successful deployments There are sometime org which will have higher version that might not supported in production. This could happen when a particular instance is in release preview and if we add new component in that org. That new component will have higher salesforce API version.

While deploying we might get errors. Changing version in Apex and VF page is easy. 


Setup-->Apex Class-->Click Edit next to class -->Version Settings -->Change version


How to change version number of Aura Component ?

1. Developer console Query Editor 

2. Query - SELECT Id, DeveloperName, ApiVersion, Description FROM AuraDefinitionBundle WHERE DeveloperName = 'your component Name'

3. Change version in the results

4. Click Save




Sunday, 12 September 2021

How to get list of users added to a queue in Apex ?

 There is no separate objects to store queue name and all queue members. They are mapped to Group and Group Member respectively. Queues are stored as records in the table Group with 'Type' as "Queue". 

Select Id from Group where type='Queue' and Name='Queue Name' - This query will return Id of queues.

Use above query results (Id)  in the query [Select UserOrGroupId From GroupMember where GroupId =:grpIdset] to fetch all the users or groups which are members of the required queue. 

We can also write both query combing 

SELECT UserOrGroupId, COUNT( Id ) FROM GroupMember WHERE GroupId IN ( SELECT Id FROM Group WHERE Type = 'Queue' ) GROUP BY UserOrGroupId
 
For User level
SELECT UserOrGroupId, COUNT( Id ) FROM GroupMember WHERE UserOrGroupId =: userfinfo.getUserid() AND GroupId IN ( SELECT Id FROM Group WHERE Type = 'Queue' ) GROUP BY UserOrGroupId 

We know Queue can be created for different objects. We have a section names supported objects, where we can select objects names.

To know which objects this queue contains then we have another standard objec

QueueSobject : - Represents the mapping between a queue Group and the sObject types associated with the queue, including custom objects.

https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_objects_queuesobject.htm

SELECT QueueId FROM QueueSobject where SobjectType in ('ObjectName','ObjectName2','ObjectName3')