Showing posts with label sfdc. Show all posts
Showing posts with label sfdc. Show all posts

Wednesday, November 30, 2022

Send an email having Apex Batch Job details after execution

 //Send an email post number of records processed successfully 

global class BatchClassName implements Database.Batchable<SObject>,Database.Stateful {

//get data in start method from querylocator

    global Database.querylocator start(Database.BatchableContext bc){

        //Query logic here

String queryStr = 'Select Query Here';

        return Database.getQueryLocator(queryStr);

    }

  //perform action in execute method on the data extracted from start method

    global void execute(Database.BatchableContext bc, List<Case> scope) {

        System.debug('scope @@@ '+scope);

        //execute logic here

    }

    // at last finish method execute to send email about execution

    global void finish(Database.BatchableContext bc) {

        

      Messaging.SingleEmailMessage m_sem = new Messaging.SingleEmailMessage();

      AsyncApexJob a = [Select a.TotalJobItems,a.Status,a.NumberOfErrors,a.JobType,a.JobItemsProcessed,a.ExtendedStatus From AsyncApexJob a WHERE id = :BC.getJobId()];

      System.debug('$$$ Jobid is '+BC.getJobId());

      List<String> emails = new List<String>{'to_emailaddress@gmail.com'};

      m_sem.setToAddresses(emails);

      m_sem.setReplyTo('reply_emailaddress@gmail.com'); 

      m_sem.setSenderDisplayName('SFDC');

      m_sem.setSubject('Processed Batch Job Status '+a.Status);

      m_sem.setPlainTextBody('The batch job has been processed: '+a.Status+' Total Job Items: '+ a.TotalJobItems+', Failures: '+a.NumberOfErrors+', Job Item processed: '+a.JobItemsProcessed+'.');

      Messaging.sendEmail(new Messaging.SingleEmailMessage [] {m_sem});

    }

}

Thursday, November 17, 2022

Hierarchy Custom Setting context in Apex

/*** Download is a checkbox in Hierarchy Custom Setting  ****/

public Hierarchy_Custom_Setting_Controller{

  public static returnType methodName(){

    Boolean isAllowed = false;  

    // Get current User custom setting. Priority 1

    Hierarchy_Custom_Setting__c userLevel = Hierarchy_Custom_Setting__c.getValues(UserInfo.getUserId());

    // Get current profile custom setting. Priority 2

    Hierarchy_Custom_Setting__c profileLevel = Hierarchy_Custom_Setting__c.getvalues(UserInfo.getProfileId()); 

    // Get current Organization custom setting. Priority 3

    Hierarchy_Custom_Setting__c orgLevel = Hierarchy_Custom_Setting__c.getvalues(UserInfo.getOrganizationId());

    

    if(userLevel != null) {

isAllowed = userLevel.Download;

    }else if(profileLevel != null) {

isAllowed = profileLevel.Download;

    }else if(orgLevel != null) { 

isAllowed = orgLevel.Download;

}

    if(!isAllowed){

        return;

}

//Logic to excute start from here

}

} 

Tuesday, November 20, 2018

Asynchronous Apex: Queueable Apex in Salesforce.com

Queueable Apex

The best features of Queueable Apex is job chaining. If you ever need to run jobs sequentially, Queueable Apex is only option.

To chain a job to another executing job, submit the second_job by using execute() method of your queueable class. You can add only one job from an executing job, which means that only one child job can exist for each parent job. 

For example, if you have a second class called Second_Job that implements the Queueable interface, you can add this class to the queue in the execute() method as follows:

Queueable Syntax:

public class SomeClass implements Queueable { 
    public void execute(QueueableContext context) {
        //awesome code here
    }
}

Chaining Jobs:

public class FirstQueClass implements Queueable { 

    public void execute(QueueableContext context) { 

        // Awesome processing logic here   
        // Chain this job to next job by submitting the next job
        System.enqueueJob(new Second_Job());

    }
}


Note: Once again, testing has a slightly different pattern. You can’t chain queueable jobs in an Apex test, doing so results in an error. 
To avoid errors, you can check if Apex is running in test context by calling Test.isRunningTest() before chaining jobs.

Scenario 1:

The following apex code takes a collection of Account records, sets the parentId for each record, and then updates the records in the database.


public class UpdateParentAccountQue implements Queueable {

    private List<Account> accounts;
    private ID parent;

    public UpdateParentAccount(List<Account> records, ID id) {

        this.accounts = records;
        this.parent = id;
    }

    public void execute(QueueableContext context) {

        for (Account account : accounts) {
        account.parentId = parent;
        
        //perform other processing or callout
        
        }
        update accounts;
    }  
}


Add this class as a job on the queue

//find all accounts in ‘NY’
List<Account> accounts = [select id from account where billingstate = ‘NY’];

//find a specific parent account for all records
Id parentId = [select id from account where name = 'ACME Corp'][0].Id;

//instantiate a new instance of the Queueable class
UpdateParentAccount updateJob = new UpdateParentAccount(accounts, parentId);

//enqueue the job for processing
ID jobID = System.enqueueJob(updateJob);

Monitor progress either through the Apex Jobs page or programmatically by querying AsyncApexJob.

SELECT Id, Status, NumberOfErrors FROM AsyncApexJob WHERE Id = :jobID

Test Class:

@isTest
public class UpdateParentAccountTest {

    @testSetup 
    static void setup() {
        List<Account> accounts = new List<Account>();
        // add a parent account
        accounts.add(new Account(name='Parent'));
        // add 100 child accounts
        for (Integer i = 0; i < 100; i++) {
            accounts.add(new Account(
                name='Test Account'+i
                ));
        }
        insert accounts;
    }
    
    static testmethod void testQueueable() {
     //Query for test data to pass to queueable class
     Id parentId = [Select Id From Account Where Name = 'Parent'][0].Id;
     List<Account> accounts = [Select Id, Name From Account Where Name Like 'Test Account%'];
     //Create our Queueable instance
     UpdateParentAccount updater = new UpdateParentAccount(accounts, parentId);
     //Test.startTest() and Test.stopTest() block to force async processes to run
    Test.startTest();        
        System.enqueueJob(updater);
    Test.stopTest();        
     //Validate the job ran. Check if record have correct parentId now
     System.assertEquals(100, [select count() from account where parentId = :parentId]);

    }

}











Asynchronous Apex: Scheduled Apex in Salesforce.com

Scheduled Apex 

Scheduled Apex lets you run Apex classes at a specified time; for example, This is ideal for daily or weekly maintenance tasks using Batch Apex. 

To invoke Apex classes at specific times, first implement the Schedulable interface for the class. Then, schedule an instance of the class to run at a specific time using the System.schedule method.

Note: Governor limits in case of asynchronous are higher as compared to synchronous. 

Schedule Apex Syntax:

global class SomeClass implements Schedulable {
    global void execute(SchedulableContext cntx) {
        // awesome code here
    }
}

Schedulable Apex

global class RemindOpptyOwners implements Schedulable {

    global void execute(SchedulableContext cntx) {
        List<Opportunity> opptys = [Select Id, Name, OwnerId, CloseDate  From Opportunity  Where IsClosed = False AND CloseDate < TODAY];
        
// Call util class and method here to create a task for each opportunity in the list
        TaskUtils.remindOwners(opptys);
    }
    
}

System.Schedule Method

It takes three arguments: 
1) Job name

2) CRON expression used to represent the time and date the job is scheduled to run

3) Instance variable of the class object

//Create a instance variable of the class object
RemindOpptyOwners reminder = new RemindOpptyOwners();

//Seconds Minutes Hours Day_of_month Month Day_of_week optional_year
String sch = '20 30 8 10 2 ?';

String jobID = System.schedule('Remind Opp Owners', sch, reminder);

Sec Min Hours Days Month WeekDay  Years 

0 0,30      * * * ? *

0 5 20 ? Jan,May Mon-Fri 2017

* --> All Values
? --> No Values


Monitoring Scheduled Jobs

It uses a job_Id variable which is returned from the System.schedule method.

CronTrigger ct = [Select TimesTriggered, NextFireTime From CronTrigger Where Id= :jobID];

Monitoring Queued Jobs

To query information about your submitted job, perform a SOQL query on AsyncApexJob by filtering on the job ID that the System.enqueueJob method returns.

AsyncApexJob jobInfo = [SELECT Id, Status, JobItemsProcessed,
 NumberOfErrors FROM AsyncApexJob WHERE Id = :jobID];

Schedule Apex Consideration:
1) You can only have 100 scheduled Apex jobs at one time, and the maximum number of scheduled Apex executions per a 24-hour period. 

2) Synchronous Web service callouts are not supported from scheduled Apex. But we can make an asynchronous callout by placing the callout in a method annotated with @future(callout=true) and call this method from scheduled Apex. 

(However, if your scheduled Apex executes a batch job, callouts are supported from the batch class.)












Asynchronous Apex: Batch Apex in Salesforce.com

Batch Apex

Batch Apex is used to run large jobs (thousands or millions of records!) that would exceed normal processing limits.
1) Every transaction starts with a new set of governor limits, which makes it easier to ensure that code stays within the governor execution limits.
2) It allow partial DML, which means if one batch fails to process successfully, all other successful batch transactions aren’t rolled back.

Batch Apex Syntax:

global class BatchClass implements Database.Batchable<sObject> {

    global Database.QueryLocator start(Database.BatchableContext bc) {
        // collect the batches of records or objects to be passed to execute
    }

    global void execute(Database.BatchableContext bc, List<P> records){
        // process each batch of records
    }    

    global void finish(Database.BatchableContext bc){
        // execute any post-processing operations
    }    

}

To Invoke a Batch Class and get Batch_id:

//1. Create an instance of batch class
MyBatchClass myBatchObject = new MyBatchClass(); 

//2. Pass instance of batch class into Database.excuteBatch method to get batch_id
Id batchId = Database.executeBatch(myBatchObject);

Id batchId = Database.executeBatch(myBatchObject, 100);

//Use batch_id to To fetch info about processing batch
AsyncApexJob job = [Select Id, Status, JobItemsProcessed, TotalJobItems, NumberOfErrors From AsyncApexJob Where Id = :batchId ];

Using Database.Stateful in Batch Apex
It is used to retain state of execution across transactions.

global class UpdateContactAddresses implements Database.Batchable<sObject>, Database.Stateful {
    
    // instance member to retain state across transactions
    global Integer recordsProcessed = 0;

    global Database.QueryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator(
            'SELECT ID, BillingStreet, BillingCity, BillingState, ' +
            'BillingPostalCode, (SELECT ID, MailingStreet, MailingCity, ' +
            'MailingState, MailingPostalCode FROM Contacts) FROM Account ' + 
            'Where BillingCountry = \'USA\''
        );
    }

    global void execute(Database.BatchableContext bc, List<Account> scope){
        // process each batch of records
        List<Contact> contacts = new List<Contact>();
        for (Account account : scope) {
            for (Contact contact : account.contacts) {
                contact.MailingStreet = account.BillingStreet;
                contact.MailingCity = account.BillingCity;
                contact.MailingState = account.BillingState;
                contact.MailingPostalCode = account.BillingPostalCode;
                // add contact to list to be updated
                contacts.add(contact);
                // increment the instance member counter
                recordsProcessed = recordsProcessed + 1;
            }
        }
        update contacts;
    }    

    global void finish(Database.BatchableContext bc){
        System.debug('Records processed===> '+recordsProcessed.);
        AsyncApexJob job = [SELECT Id, Status, NumberOfErrors, 
            JobItemsProcessed,
            TotalJobItems, CreatedBy.Email
            FROM AsyncApexJob
            WHERE Id = :bc.getJobId()];
        // call some utility to send email
        EmailUtils.sendMessage(a, recordsProcessed);
    }    

}

Testing Batch Apex

@isTest
private class UpdateContactAddressesTest {

    @testSetup 
    static void setup() {
        List<Account> accounts = new List<Account>();
        List<Contact> contacts = new List<Contact>();
        // insert 10 accounts
        for (Integer i=0;i<10;i++) {
            accounts.add(new Account(name='Account '+i, 
                billingcity='New York', billingcountry='USA'));
        }
        insert accounts;

        // find the account just inserted. add contact for each
        for (Account account : [select id from account]) {
            contacts.add(new Contact(firstname='first', 
                lastname='last', accountId=account.id));
        }
        insert contacts;
    }

    static testmethod void test() {        
        Test.startTest();
        UpdateContactAddresses uca = new UpdateContactAddresses();
        Id batchId = Database.executeBatch(uca);
        Test.stopTest();

        // after the testing stops, assert records were updated properly
        System.assertEquals(10, [select count() from contact where MailingCity = 'New York']);
    }    
}

Abort Running Batch

1) Abort one Apex Batch Job by Job_Id.
Setup -> Monitoring -> Apex Jobs to get Batch Job Id.
Finally run below statement from anonymous block.

//pass JobId to System.abortJob() method
System.abortJob(JobID);

2) Abort bulk Apex Job by Job_Id.

// Loop through jobs located by name that we need to abort
List<CronTrigger> jobsToAbort = [Select Id, CronJobDetail.Name, CronJobDetail.JobType From CronTrigger Where CronJobDetail.Name like 'WorkOrder%'];

for(CronTrigger ct : jobsToAbort){
// abort the job, try/catch because the job might not exist
    try {
        system.abortJob(ct.id);
    } catch (exception e) {

System.debug('Exception Message: '+e.getMessage());

}
}


Batch Apex Consideration

1) Up to 5 queued or active batch jobs are only allowed.

2) A maximum of 50 million records can be returned in the Database.QueryLocator object. If more than 50 million records are returned, the batch job is immediately terminated and marked as Failed

3) If no size is specified as optional scope parameter of Database.executeBatch, Salesforce breaks the records returned by the start method into batches of 200, and then passes each batch to the execute method. 
Note: Apex governor limits are reset for each execution of execute.

4) The start, execute, and finish methods can implement up to 10 callouts each

5) The maximum number of batch executions is 250,000 per 24 hours

6) Only one batch Apex job's start method can run at a time in an organization. Batch jobs that haven’t started yet remain in the queue until they're started. 











Asynchronous Apex: Future Method in Salesforce.com

Future Method

1) Making callouts to external web services. 
i.e. When we are making callouts to external web services from a trigger or after performing a DML operation, we must use a future or queueable method.

2) Process we want to run in its separate thread in the back-end.
i.e. When we are working on some sort of resource consuming calculation or processing of records.

3) Isolating DML operations on different types of sObject.
i.e. When we are performing DML on setup and non-setup sObject types, it isolates DML to prevent the "Mixed DML Errors".


Future Method Syntax:
global class FutureClass {
     @future
     public static void futureMethod(List<Id> recordIds) {
     List<Account> accounts = [Select Id, Name from Account Where Id IN :recordIds];
     // process account records to do awesome stuff
     }
}


Future Method Considerations

1) Future methods must be static methods and return a void.

2) Parameters must be primitive data types, arrays of primitive data types, or collections of primitive data types.
Note:- Future methods can’t take standard or custom objects as arguments.

3) Common pattern is to pass a List<record IDs> that you want to process asynchronously.

4) Future methods can’t be used in Visualforce controllers in getMethod(), setMethod(), nor in the constructor.

5) You can’t call a future method from a future method.

6) You can not invoke a trigger that calls a future method while running a future method.

7) The getContent() and getContentAsPDF() methods can’t be used in future method.

8) You’re limited to 50 future calls per Apex invocation.

9) To test future methods, enclose your test code between the test.startTest() and test.stopTest() test methods.


Saturday, November 17, 2018

REGEX function, Validation Rule in Salesforce.com

REGEX or Regular Expression in Salesforce

REGEX(Input_Field_Name, 'Input_Format_Expression')

i.e. BLKPR7234B or blkpr7234b: 

NOT REGEX( PAN_Number__c , '[A-Z,a-z]{5}[0-9]{4}[A-Z,a-z]{1}' )

This function is Boolean, which is used to compare text format between the input text and the specified expression. If both the text format and expression are equal, then it returns true, else it returns false.

Prepare the regular expression by using wild-card characters as below.

[ ] --> Indicates a collection of characters

[A-Z] --> Indicates a collection of characters falls
between A-Z.

[a-z] --> Indicates a collection of characters falls
between a-z.

[A-Z,a-z] --> Indicates a collection of characters falls
between A-Z or a-z or combination of both.

[0-9] --> Indicates a Number, where each digit should be
falls between 0-9.

{Number} --> Indicates the Number of characters should be 
used in the string.

[JKL] --> Indicates a collection of characters, where
each characters should be either J/K/L.

 -  --> Represents a Single Character.

PAN Number Format: BLKPR 7234 J

BLKPR --> 5
7234   --> 4
J         --> 1

BLKPR7234J:
Format: [A-Z]{5}[0-9]{4}[A-Z]{1}


bLkPr7234j: 
Format: [A-Z,a-z]{5}[0-9]{4}[A-Z,a-z]{1}

//Create a validation rule, to validate the PAN Number format.
Validation Condition: 

i.e. BLKPR7234B or blkpr7234b: 

NOT REGEX( PAN_Number__c , '[A-Z,a-z]{5}[0-9]{4}[A-Z,a-z]{1}' )













Thursday, November 8, 2018

Bulkified and Non-Bulkified Apex Code concepts in Salesforce.com

Non-Bulkified code:
It can not process large set of data and eventually can hit governor limit because it works on one record.

For example: It can process only one (first) account record from the Trigger.new collection, but if more than one account has initiated this trigger, then those additional records will not be processed.

trigger nonBulkifiedTrigger on Account (before insert, before update) {

   //It can get only first record from the collection


   Account acct = Trigger.new[0];
   List<Contact> contacts = [Select id, firstname, lastname, email 
                                                        From Contact 
                                                        Where accountId = :acct.Id];
   
}

Bulkified Code:
It can process large set of data and escape governor limit because it works on list of records.

For example: It can process all account record from the Trigger.new collection.

trigger bulkifiedTrigger on Account (before insert, before update) {

    //Loop through all records in the Trigger.new collection
    for(Account a: Trigger.new){

    //Concatenate the Name and billingState into the Description field
    a.Description = a.Name + ':' + a.BillingState
   }
}










Handle exception by Try, Catch and Finally statement in Apex in Salesforce.com

Try-Catch-Finally Statements Syntax:

try {

      //Perform some operation that might cause an exception.

} catch (exception e){ 

      //Handle generic exception here.

} 
catch (dmlexception de){ 

      //Handle dml exception here.

} finally { 

      //this block of code always execute and allows you to clean up your code.

}

Apex Code

try {
  // Perform some operation that might cause an exception.
    Merchandise__c m = new Merchandise__c();
    insert m;

    // This doesn't execute since insert causes an exception
    System.debug('Statement after insert.');

} catch (Exception e) {
    
   // Handle generic exception here.
   }catch(DmlException e) {
    System.debug('The following exception has occurred: ' + e.getMessage());
    
 } finally {
    // Perform some clean up.
}










DML Statement vs Database Class Method in Salesforce.com

DML Statement:
It does not support partial execution, which means if an error encountered an apex records execution at that moment whole execution will rolled back and throw error messages. Use try and catch block to handle exceptions and  throw error messages as well. 

Database Class Methods:

It supports partial execution, which means if an error encountered an apex records execution at that moment the records causing errors will be expelled from execution, and successfully executed record will be processed. 

Note: Database.Insert(Boolean);


Partial ==> Database.Insert (false)

No Partial ==> Database.Insert (true)

ApexCode1A


// Create the list of sObjects to insert
List<Account> acctList = new List<Account>();
acctList.add(new Account(Name='Acme1'));
acctList.add(new Account(Name='Acme2'));

// DML statement

insert acctList;

ApexCode1B


// Create the list of sObjects to insert
List<Account> acctList = new List<Account>();
acctList.add(new Account(Name='Acme1'));
acctList.add(new Account(Name='Acme2'));

// DML statement (Partial)

Database.SaveResult[] srList = Database.insert(acctList, false);

// Iterate through each returned result

for (Database.SaveResult sr : srList) {
    if (sr.isSuccess()) {
        // Operation was successful, so get the ID of the record that was processed
        System.debug('Successfully inserted account. Account ID: ' + sr.getId());
    } else {
        // Operation failed, so get all errors               
        for(Database.Error err : sr.getErrors()) {
            System.debug('The following error has occurred.');                   
            System.debug(err.getStatusCode() + ': ' + err.getMessage());
            System.debug('Account fields that affected this error: ' + err.getFields());
        }
    }
}

SaveResult Methods (Instance Methods)

* getErrors()
* getId()
* isSuccess()










Best Practices for writing Apex Test Class in Salesforce.com

Best Practices for writing Apex Test Class

1) Use @isTest keyword to declare apex test class and methods.

2) Use @testSetup to set up test data required for testing.

3) Use @TestVisible in apex controller method defined as private, so it can be accessed in test class.

4) Use System.runAs(user) to test apex on profile level.

5) Avoid using SeeAllData = true because it allows test methods to access database records for testing, resulting it can fail in production where database not having corresponding records.

Note: Only use SeeAllData = true, if there are sObjects that doesn't allow DML operation. e.g. PriceBook creation.

6) Use Test.startTest and Test.stopTest to reset the governor limit, and also to forces the asynchronous methods to execute synchronously, so that the results can be asserted.

7) Use System.assertEquals(expected, actual, msg) and System.assertNotEquals(expected, actual, msg) to assert expected and actual values from test methods.

8) Avoid Hard Code Ids of any sObject in any test method.

9) Use Null Pointer Exception test as part of negative testing for each method, specially the methods which takes parameters.


Test class important keywords are 
  • @isTest
  • @testSetup
  • @TestVisible
  • System.runAs(user)
  • SeeAllData = true
  • Test.startTest and Test.stopTest
  • System.assert(condition, msg)
  • System.assertEquals(expected, actual, msg)
  • System.assertNotEquals(expected, actual, msg)









Best Practices for writing Apex Code in Salesforce.com

Best Practices for writing Apex Code

1) Bulkify your controller code.

2) Use static and transient keyword for variable if possible.

3) Avoid SOQL queries inside for loops.

4) Avoid DML statements inside for loops.

5) Bulkify your helper methods.

6) Use collections like list, set and map to store data.

7) Use streamline queries and efficient for loops to process large set of data.

8) Use limits in SOQL to avoid hitting governor limits.

9) Use @future appropriately to execute code in separate thread.

10) Use batch apex or queueable apex to manipulate large set of data in batches.

11) Avoid hard code IDs.

12) Use try and catch block to handle exception, and throw error messages.











Apex Trigger, Trigger Events, Trigger Context Variables in Salesforce.com

Trigger is an apex code which execute before and after a record is Inserted/Updated/Deleted from salesforce database. 

Trigger Syntax:
Trigger <trigger_name> on <Object_Name> (trigger Events) {
           
          // Logic here

}

Trigger Types:
1) Before Trigger
- It is used to perform the DML (Insert/Update/Delete) on same object and data validation functionality.
- It executes before data commit to database.

2) After Trigger
- It is used to perform the DML (Insert/Update/Delete) on cross object.
- It executes after data commit to database.

Note: In after trigger, we get "run time exception" whenever the user tries to modify any field record of the same object.


DML (Data Manipulation Language):

1) Insert
2) Update
3) Delete
4) Undelete


Trigger events:

1) for Insert
before insert
after insert

2) for Update
before update
after update

3) for Delete
before delete
after delete

4) for Undelete
after undelete


Trigger Context Variable:
Trigger context variable are used when you want to use different logic at different events. 

1) isInsert: Returns true if this trigger was fired due to an insert operation.

2) isUpdate: Returns true if this trigger was fired due to an update operation.

3) isDelete: Returns true if this trigger was fired due to a delete operation.

4) isBefore: Returns true if this trigger was fired before any record was saved.

5) isAfter: Returns true if this trigger was fired after all records were saved.

6) New: Returns a list of the new versions of the sObject records.

7) Old: Returns a list of the old versions of the sObject records.

8) NewMap: Returns a map of IDs to the new versions of the sObject records. (map<id, newRecords>)

9) OldMap: Returns a map of IDs to the old versions of the sObject records.(map<id, oldRecords>)

10) isExecuting: Returns true if the current context for the Apex code is a trigger.


11) Size: The total number of records in a trigger invocation, both old and new.

Note: All trigger context variables are written as Trigger.contextVariable such as Trigger.isInsert, etc...

Trigger Events using Context variables:

1) for Insert
before insert: Trigger.New
after insert: Trigger.New

2) for Update
before update: Trigger.New and Trigger.Old
after update: Trigger.New and Trigger.Old

3) for Delete
before delete: Trigger.Old
after delete: Trigger.Old

4) for Undelete
after undelete: Trigger.New










Workflow Rule Salesforce.com

Workflow Rules automates 4 actions:
1) Field Updates: Update the value of a field on a record.

2) Email Alerts: Send an email to one or more recipients you specify.

3) Tasks Assignment: Assign a new task to a user, role, or record owner.

4) Outbound Messages: Send a secure, configurable API message (in XML format) to a designated listener.

For example, 
a) Assign follow-up tasks to a support representative one week after a case is updated.

b) Send sales management an email alert when a sales rep qualifies a large deal.

c) Change the Owner field on a contract three days before it expires.

d) Trigger an outbound API message to an external HR system to initiate the reimbursement process for an approved expense report.

Each workflow rule consists of:
1) Object: Opportunity

2) Evaluation Criteria: Which cause to execute Workflow Rule.
a) Created
           b) Created, and every time edited.
           c) Created, and any time edited to subsequently meet the criteria.

3) Rule Criteria (Filter Conditions):
Run this rule if the following criteria is met.
(Opportunity: Amount greater or equal 1000,000) &&
(Opportunity: Stage equals Closed Won)

4) Immediate actions that execute when a record matches the criteria.
          For example, Salesforce.com can automatically send an email that notifies the account team when a new high-value opportunity is created.

5) Time-dependent actions that queue when a record matches the criteria, and execute according to time triggers.
  For example, Salesforce.com can automatically send an follow up email to the account team if a high-value opportunity is still open ten days before the close date.

Important to Remember:
1) One object can have only 50 Active Workflow Rules.

2) Each Workflow Rule can perform
             10 Field Update
             10 Email Alert
             10 Task Assignment
             10 Outbound Messages
in context of both immediate and time dependent actions.

3) In Workflow Rule, Field Update action can update child record only, if objects are having Master-Detail relationship in between.

4) Time Dependent Action is not allowed, if criteria is "Created, and every time edited".










Wednesday, November 7, 2018

Lookup, Master-Details and Many to Many Relationships in Salesforce.com

Lookup relationship:
1) Lookup relationship provides One to Many relationship between the objects by default. (i.e. A parent record can have Many associated child records.)

2) Upon creating the child record, lookup field is optional by default. (i.e. Lookup field is not required upon creating the child records)

3) Lookup relationship allow re-parenting of the associated child records by default. (i.e. we can change the parent of the child records)

4) Upon deleting the lookup parent record, associated child records will not be deleted.

5) We can make the lookup field mandatory by selecting "Required" checkbox, when creating the relationship field on child object.

6) To delete parent object of lookup relationship having associated child record is not allowed. (To delete it, first we need to re-parent all associated child records with other parent record)

7) We can create the lookup relationship on an object which already contains records.

8) We can have max. of 40 lookup relationships per an object.

9) In lookup relationship, parent and child records will have the owner fields (both records having owner). 

10) Sharing setting and security settings of parent will not enforce child and vice-versa.

11) Standard object can only be a child of custom object in lookup relationship only.


Master-Detail relationship:
1) Master-Detail relationship will provides one-to-many relationship between the objects by default. (i.e. A parent record can have zero or more child records)

2) We can't create the Master-Detail relationship on a child objects already having records.

3) Upon creating the child record, selecting the parent record is mandatory. (i.e. Lookup field is a required field)

4) Re-parenting option is not allowed in Master-Detail association by default. (We need to enable it manually, by selecting the "Allow Re-Parenting" checkbox upon creating the field.)

5) An object can have max. of 2 Master-Detail relationship fields.

6) Only parent record will have the "Owner" field but child records will not have the "Owner" field. (i.e Parent record and child record will have same owner)

7) Sharing settings and Security settings of the child record will be depends upon the parent record.

8) Upon deleting the parent record, all the associated child records will deleted automatically.

9) Standard object can not be child of Custom object in Master-Detail relationship.


Predefined Lookup and Master-Details relationship between standard objects:

The relationship between standard objects are either Lookup or Master-Detail.

1) Account and Contact:
Between Account and Contact, Salesforce provides the Lookup Relationship.

Account --> Parent
Contact --> Child

Note1: We have lookup field "AccountId" on child object (contact), which is Id of parent object (Account).

Note2: Upon deleting account record, all the associated contact records will get deleted automatically.

Note3: We can prevent the deletion of contact records by using "Triggers". (i.e. Before deleting the Account, We need to get all the associated Contacts and make the "AccountID" field value as blank.) 

2) Account and Opportunity:
Between Account and Opportunity, Salesforce provides "Master-Detail" association.

Account --> Parent
Opportunity --> Child

Note1: We have lookup field "AccountId" on child object (Opportunity), which is Id of parent object (Account).

3) Account and Case:
Between Account and Case object, we have Lookup Relationship.

Account --> Parent
Case --> Child.

Note1: We have lookup field "AccountId" on child object (Case), which is Id of parent object (Account).
Once We map the association between the objects by using either Lookup or Master-Detail, in future we can change the relationship type from Lookup to Master-Detail and vice-versa.

Many to Many relationship:

In few cases, we have to map Many to Many relationship between two objects, which provides One to Many association from both the sides.

Ex: Let's consider two objects Mobile and EarPhone, where a Mobile supports multiple EarPhone and vice-versa.

In Salesforce, we can't map Many-to-Many relationship between two objects directly. Therefore, to achieve this property, we need to create a 'Junction object', which will have Master-Details relationship with both objects.

Predefined Many to Many relationship between standard objects:

1) CampaignMember: Between Campaign and Contact object. 

2) OpportunityContactRoles: Between Contact and Opportunity object.

3) OpportunityLineItem: Between Opportunity and Product object.

4) PricebookEntry: Between Product and Pricebook object.










Validation in flow input text field in sfdc: Maximum 255 characters limit

The input text field validate in sfdc flow behaves opposite of the generic sfdc validation rule.  Here the validation formula is evaluating ...