Showing posts with label apex. Show all posts
Showing posts with label apex. Show all posts

Thursday, 20 July 2023

Salesforce's New Assert Class


Introduction To The New Assert Class

  • The Assert class is designed to provide clearer assertions within Apex test code and make it easier for developers to write more maintainable test code.
  • This new class offers multiple static methods and is intended to be a dedicated location for assert methods.
  • The addition of this class means that developers will have all the assert methods they need in one place.
  • Starting with “Assert” is more intentional and readable, making the test code cleaner.
  • Although Apex still allows the use of System assert methods.


Code Example of New Assert Class

  • The above code demonstrates the use of Old and new Equality assertions and Expression true Assertion. 
  • As in the code, we are using the same system assert method for Equality and Expression true assertion using different statements while the new Assert class provides two different methods for Equality and Expression true assertion which makes the code more intentional.


  • The above code represents the use of Not null and Instance of type assertions where the use of these two assertions makes the code more readable. 
  • There are two other assertion methods in the new assert class such as Assert.isNull(value, msg), Assert.isNotInstanceOfType(instance, System.notExpectedType, msg). 
  • If you noticed, like old assertion methods, the new Assertion methods also include an assertion message. 

  • The above test class method includes the Error Testing Assertions where the same assert method is used for error testing in the old assertion way but the new assert class provides the specific method. 


Conclusion

The new assert class provides an improved and more efficient way to write assertions, resulting in better testing and higher code quality.



If you have any questions you can reach out our Salesforce Consulting team here.

Thursday, 26 May 2022

Setting up merge fields and sending emails using email template on the custom object through apex


SCENARIO

While working on one of the requirements for a Service sector project for a client based out of Atlanta, GA, there was a requirement to send an email using an email template where the related entity type was the custom object.

CHALLENGE

In SingleEmailMessage, if we set template-id (using setTemplateId), then target object id is required. setTargetObjectId() can accept contact, lead, user or person account id only. We cannot pass the custom object id in the parameter of setTargetObjectId() - reference link. Also, the custom object is not having any relationship to any of these standard objects.

APPROACH

With a little magical Apex hand-waving, we can indeed send emails using custom email templates.

The key thing we used here is Salesforce doesn't send an email immediately when the sendEmail() method is executed, instead, Salesforce waits for the very end of the transaction. If we roll back the transaction, Salesforce doesn't send the email at all.

Below is the text value of the email template having some merge fields that we want to populate automatically,

Hi {{{Sourcing__c.Full_Name__c}}},

Good afternoon, I hope you are having a great day, and that this email finds you well. 

I just wanted to reach out to follow up with you about your application for one of
our Entry-Level IT Career Opportunities. We are very interested in speaking with you.

Our initial phone call takes less than 10 minutes. You can reach me on my direct line,
{{{Sender.Phone}}} If for some reason I do not answer please leave a voice mail
and reply to this email. 

Regards,
{{{Sender.Signature}}}

Below is a code we used for sending emails,

public class SendEmailSourcing{
    
    public void sendEmailMessage(){
	// Fetching email template
        EmailTemplate emailTemplate = [SELECT Id, DeveloperName, Subject, HtmlValue, Body
                                       FROM EmailTemplate WHERE Name = '1st Call - Email' LIMIT 1];
									   
	// Picking a dummy contact where email is not null
        Contact con = [SELECT Id, Email FROM Contact WHERE email <> NULL LIMIT 1];    
        
        List<Messaging.SingleEmailmessage> emailMessages = new List<Messaging.SingleEmailMessage>();
        List<Messaging.SingleEmailmessage> emailMessagesToSend = new List<Messaging.SingleEmailMessage>();
        Messaging.SingleEmailmessage email = new Messaging.SingleEmailmessage();  
        
	// For every sourcing record, creating email message and adding it to the list of email messages
        for (Sourcing__c sourcing :  sourcingList) {                
		email = new Messaging.SingleEmailmessage();
		email.setTemplateId(emailTemplate.Id);
		email.setTargetObjectId(con.Id);
		email.setWhatId(sourcing.Id);
		email.setToAddresses(new List<String>{sourcing.Email__c});
		email.setTreatTargetObjectAsRecipient(false);
		email.setUseSignature(false);
		emailMessages.add(email);
	}       
        
	// Setting save point to rollback the transaction after sending email message
        Savepoint sp = Database.setSavepoint();
        Messaging.sendEmail(emailMessages);
        Database.rollback(sp);
        
	// Copying content of the each email message that we just sent using sendEmail() and rolled back
	// and sending these new messages
        for (Messaging.SingleEmailMessage singleEmail : emailMessages) {
		email = new Messaging.SingleEmailMessage();
		email.setToAddresses(singleEmail.getToAddresses());
		email.setPlainTextBody(singleEmail.getPlainTextBody());
		email.setHTMLBody(singleEmail.getHTMLBody());
		email.setSubject(singleEmail.getSubject());
		email.setWhatId(singleEmail.getWhatId());
		email.setUseSignature(false);
		email.setSaveAsActivity(true);
		emailMessagesToSend.add(email);
        }
		
        Messaging.sendEmail(emailMessagesToSend);  
    }
	
}

In the above code, first, we created email message for each sourcing record and added it to the list of email messages. Then trying to send email messages in a transaction that can be rolled back.

After rolling back the transaction, we are iterating through all the emails we just sent and are copying the content of those emails into another list of emails.

That newly created list is then used to send the emails.

CONCLUSION

Using Apex effectively and rolling back the transaction, we are able to set merge fields and send email messages using email templates where a related entity type is a custom object.

If you have any questions you can reach out our Salesforce Consulting team here.

Thursday, 3 February 2022

Retrieve Custom Metadata Type Records Using Static Methods

With salesforce Spring21 release , there is no need to write a Salesforce Object Query Language (SOQL) to access Custom Metadata Type in Apex. Salesforce introduces new methods as similar to accessing custom settings. 

Before Spring21 release, To access Custom Metadata Type Record only using SOQL in Apex like below,

// Before Spring 21
List<Country_Code__mdt> listCountryCode = [SELECT Id,Label,MasterLabel,Country_Code__c,DeveloperName from Country_Code__mdt];
      
for(Country_Code__mdt c : listCountryCode){
           System.debug('Label ->'+ c.Label + ',' + 'Country code ->' + c.Country_Code__c + ',' +'Devloper name ->' + c.DeveloperName);
      }
/* OUTPUT
 * Label -> CANADA,Country code ->CAN,Devloper name ->CANADA
 * Label -> INDIA,Country code ->IND,Devloper name ->INDIA
 * Label -> UNITED STATES,Country code ->UNS,Devloper name ->UNITED STATES
*/

Salesforce spring21 release provides an option to access Custom Metadata Type record using static methods without SQOL.

Using Apex getAll(), getInstance(recordId), getInstance (qualifiedApiName), and getInstance(developerName) methods are used to retrieve information from custom metadata type records faster. These methods don’t rely on the SOQL engine and return the sObject details directly by the call. Below are few benefits of these methods.
  • It removes need of Salesforce Object Query Language (SOQL).
  • Eliminate any SOQL limits.
  • Build the code cleaner and faster.
Let's see all methods with example.
  • getAll()
It returns a map containing custom metadata records for the specific custom metadata type. The map's keys are the Record ID and the map’s values are the sObjects record.

List<Country_Code__mdt> listCountryCode = Country_Code__mdt.getAll().values();
      
for(Country_Code__mdt c : listCountryCode){
           System.debug('Label ->'+ c.Label + ',' + 'Country code ->' + c.Country_Code__c + ',' +'Devloper name ->' + c.DeveloperName);
      }
/* OUTPUT
 * Label -> CANADA,Country code ->CAN,Devloper name ->CANADA
 * Label -> INDIA,Country code ->IND,Devloper name ->INDIA
 * Label -> UNITED STATES,Country code ->UNS,Devloper name ->UNITED STATES
*/
  • getInstance(recordId)
It returns a single custom metadata type sObject record for a specified record ID.

Country_Code__mdt CountryCodeRecord = Country_Code__mdt.getInstance('m022w000000lPl8AAE');
System.debug('Label ->'+ CountryCodeRecord.Label + ',' + 'Country code ->' + CountryCodeRecord.Country_Code__c);
/*OUTPUT
 * Label ->CANADA,Country code ->CAN
*/
  • getInstance(developerName)
It returns a single custom metadata type sObject record for a specified developerName field of the custom metadata type object.

Country_Code__mdt CountryCodeRecord = Country_Code__mdt.getInstance('CANADA');
System.debug('Developer Name ->'+ CountryCodeRecord.DeveloperName + ',' + 'Country code ->' + CountryCodeRecord.Country_Code__c);
/*OUTPUT
 * Developer Name->CANADA,Country code ->CAN
*/
  • getInstance(qualifiedApiName)
It returns a single custom metadata type sObject record for a qualified API name specified as parameter.

Country_Code__mdt CountryCodeRecord = Country_Code__mdt.getInstance('INDIA');
System.debug('Label ->'+ CountryCodeRecord.Label + ',' + 'Country code ->' + CountryCodeRecord.Country_Code__c);
/*OUTPUT
 * Label->INDIA,Country code ->IND
*/
 

If you have any questions you can reach out our Salesforce Consulting team here.

Thursday, 7 January 2021

Auto-update case owner of multiple records from list view in Service Console Application

Requirement:

Recently working with Service Console Application, came across a requirement where we need to auto update the Case Owner 
to current logged in user for all the selected case records from the list view. Along with that, we also need to implement it in a such way, so on auto assigning of the records, selected records should be opened in new tabs in a Service Console Application.

Challenge:

Using OOTB features of Salesforce, we can manually update the case owner of only one record at a time. However, in our case, we need to update multiple records with auto assigning of case owner with current logged in user.

Solution:

To achieve this,
  • We need to create a Custom List Button with a content source as a Visualforce page and added it to the Search Layout.
  • Basically, this visualforce page calls an action method from the APEX class and retrieves all the selected records and update case owner of each record based on the current logged in user.
  • We also need to implement JavaScript using Console API to open each updated record in new tab in Service Console Application.
  • The console API versions 42.0 and above of the Salesforce Console Integration Toolkit are supported in the Lightning Console JavaScript API.

ChangeCaseOwnerController Apex Class:

public class ChangeCaseOwnerController { 
    
    ApexPages.StandardSetController setCon; 
    public List<case> listofcases {get; set;} 
    public List<case> returnlist {get; set;} 
    public Map<string,string> returnMap {get; set;} 
   
    public ChangeCaseOwnerController(ApexPages.StandardSetController controller) { 
        setCon = controller; 
        listofcases = (List<case>)controller.getSelected(); //will fetch the selected records from record list
    }

    // method will update the owner of records assigned in listofcases 
    public PageReference changeOwner(){ 
        PageReference pref;
        list<case> caselist = new list<case>();       
 
        for(case c : listofcases){
            c.ownerId = UserInfo.getUserId();
            caselist.add(c);
        } 

        if(caselist.size() > 0){
            try { 
                    update caselist;            
                    returnMap = new Map<string,string>(); 
                    returnlist = [select id,CaseNumber from Case where id IN : lstcase ];  
                    for(Case casechild:  returnlist){ 
                         returnMap.put(casechild.id,casechild.CaseNumber); 
                     }
                  }  
           }
                 catch(DmlException e) { 
                      System.debug('The following Error exception has occurred: ' + e.getMessage());
          } 
       return null; 
    } 
} 

ChangeCaseOwner Visualforce Page:

<apex:page standardController="Case" recordSetVar="cases" extensions="ChangeCaseOwnerController" showHeader="false" action="{!changeOwner}"> 

    <!--include scripts from Salesforce Console Integration Toolkit: --> 
    <script src="../../soap/ajax/48.0/connection.js" type="text/javascript"></script>
    <script src="/support/console/48.0/integration.js" type="text/javascript"></script> 

    <script type="text/javascript">

    var mapofCases = '{!returnMap}'; // assign the map with Case Id and Case Number to variable
    mapofCases=  mapofCases.replace('{',''); 
    mapofCases= mapofCases.replace('}','');
    console.log(mapofCases); 
    var splitArray = mapofCases.split(","); 
 
    openTab(); //calling the function after getting separate case ids

    function openTab(){
        for (var i=0; i < splitArray.length; i++) {            
        openPrimaryTab(splitArray[i]); 
        }
    }

    function openPrimaryTab(arrayid) {
       var caseid=  arrayid.split("=")[0].trim(); 
       var casenumber=  arrayid.split("=")[1].trim();
       sforce.console.openPrimaryTab(undefined,'/'+caseid, true, casenumber);
    }
    </script>
</apex:page> 

Once APEX class and Visualforce page are created, we need to create a Custom List Button. To create a button, 
  • Go to Setup > Object Manager > Case > Buttons, Links, and Actions > New Button  
  • Set Name/Label Select List Button > Content Source Visualforce Page > Content Select Visualforce Page [ChangeCaseOwner]. 

Once all above steps are setup and configured properly, we can see the desired results as shown in below video.
 
Output:


If you have any questions you can reach out to our Salesforce Consulting team here.