Thursday, November 30, 2017

Trigger to count events related to an Account

The following trigger will count the number of events related to an account.
The trigger will execute whenever an event is created/updated/deleted and is related to account.

trigger EventCount on Event (after insert, after update, after delete, after undelete) {
    Map<Id, List<Event>> mapAcctIdEventList = new Map<Id, List<Event>>();//Map to maintain new events for an account
    Map<Id, List<Event>> mapAcctIdDelEventList = new Map<Id, List<Event>>();//Map to maintain deleted events for an account
    Set<Id> AcctIds = new Set<Id>();   
    List<Account> listAcct = new List<Account>();
   //If an event is inserted and is related to account
    if(trigger.isInsert) {
        for(Event eve : trigger.New) {
            if(String.isNotBlank(eve.WhatId)) {
                Id WhatIdObj = eve.WhatId;
                if(whatIdObj.getsObjectType() == Account.sObjectType)
                {
                    if(!mapAcctIdEventList.containskey(eve.WhatId)) {                   
                        mapAcctIdEventList.put(eve.WhatId, new List<Event>());
                    }
                    mapAcctIdEventList.get(eve.WhatId).add(eve);
                    AcctIds.add(eve.WhatId);
                }
            }         
        } 
    }
   
//If an event is updated  1) If RelatedTo is changed from one account to other account 2)If RelatedTo is previously populated and changed to blank.
    if(trigger.isUpdate) {
        for(Event eve : trigger.New) {
            if(String.isNotBlank(eve.WhatId) && eve.WhatId != trigger.oldMap.get(eve.Id).WhatId) {
                Id WhatIdObj = eve.WhatId;
                if(whatIdObj.getsObjectType() == Account.sObjectType)
                {
                    if(!mapAcctIdEventList.containskey(eve.WhatId)){
                        mapAcctIdEventList.put(eve.WhatId, new List<Event>());
                    }
                    mapAcctIdEventList.get(eve.WhatId).add(eve);
                    AcctIds.add(eve.WhatId);
                    if(trigger.oldMap.get(eve.Id).WhatId!=null)
                    {
                        if(!mapAcctIdDelEventList.containskey(trigger.oldMap.get(eve.Id).WhatId)){
                            mapAcctIdDelEventList.put(trigger.oldMap.get(eve.Id).WhatId, new List<Event>());
                        }
                        mapAcctIdDelEventList.get(trigger.oldMap.get(eve.Id).WhatId).add(eve); 
                        AcctIds.add(trigger.oldMap.get(eve.Id).WhatId);
                    }
                }             
            } else if(String.isBlank(eve.WhatId) && String.isNotBlank(trigger.oldMap.get(eve.Id).WhatId)) {
                Id WhatIdObj = eve.WhatId;
                if(whatIdObj.getsObjectType() == Account.sObjectType)
                {
                    if(!mapAcctIdDelEventList.containskey(eve.WhatId)){
                        mapAcctIdDelEventList.put(trigger.oldMap.get(eve.Id).WhatId, new List<Event>());
                    }
                    mapAcctIdDelEventList.get(trigger.oldMap.get(eve.Id).WhatId).add(eve); 
                    AcctIds.add(trigger.oldMap.get(eve.Id).WhatId);
                }
            }
        } 
    }
   //If an event is undelete an event is added to account 
    if(trigger.isUndelete) {
        for(Event eve : trigger.new) {
            if(String.isNotBlank(eve.WhatId)){
                Id WhatIdObj = eve.WhatId;
                if(whatIdObj.getsObjectType() == Account.sObjectType)
                {
                    if(!mapAcctIdEventList.containskey(eve.WhatId)){
                        mapAcctIdEventList.put(eve.WhatId, new List<Event>());
                    }
                    mapAcctIdEventList.get(eve.WhatId).add(eve);   
                    AcctIds.add(eve.WhatId);
                }
            }
        } 
    }     
    //If an event is deleted
    if(trigger.isDelete) {
        for(Event eve : trigger.Old) {
            if(String.isNotBlank(eve.WhatId)){
                Id WhatIdObj = eve.WhatId;
                if(whatIdObj.getsObjectType() == Account.sObjectType)
                {
                    if(!mapAcctIdDelEventList.containskey(eve.WhatId)){
                        mapAcctIdDelEventList.put(eve.WhatId, new List<Event>());
                    }
                    mapAcctIdDelEventList.get(eve.WhatId).add(eve);   
                    AcctIds.add(eve.WhatId);
                }
            }
        } 
    } 
   
    if(AcctIds.size() > 0) {
        listAcct = [SELECT Id, Activity_Count__c FROM Account WHERE Id IN : AcctIds];
       
        for(Account acct : listAcct) {
            Integer noOfevets = 0;
            if(mapAcctIdEventList.containskey(acct.Id)) {
                noOfevets += mapAcctIdEventList.get(acct.Id).size();
            }
            if(mapAcctIdDelEventList.containskey(acct.Id)) {       
                noOfevets -= mapAcctIdDelEventList.get(acct.Id).size();       
            }
            acct.Activity_Count__c = acct.Activity_Count__c == null ? noOfevets : (acct.Activity_Count__c + noOfevets);
                }
       
        update listAcct;   
    }
}

Tuesday, June 30, 2015

Trigger : Throw an error if we try to update an Account with contacts

Recently I got a requirement on Triggers.Trigger should trow an error if we try to update an Account which contains child contacts.
Update should be successful if Account does not contains any child Contacts.
I felt some how difficulty in writing this trigger by considering governor limits and optimizing the use of collections but I managed to write the trigger successfully.. After writing this trigger I wanted to share it with others and here is the trigger.

trigger AccountsWithContacts on Account (before update) {
    
    Set<Id> accWithContacts = new Set<Id>();
    for(Contact c: [Select Id,Name,AccountId from Contact Where AccountId In: Trigger.NewMap.KeySet()])
    {
        accWithContacts.add(c.AccountId);
    }
    
    for(Account acc:Trigger.New)
    {
        if(accWithContacts.Contains(acc.Id))
            acc.addError('could not update Account with contacts');
    }

}



Monday, June 22, 2015

Difference between apex:message,apex:messages,apex:pageMessage and apex:pageMessages in salesforce

We have different components that supports displaying messages in a visual force page like <apex:message>,<apex:messages>,<apex:pageMessage> and <apex:pageMessages>. Let us see how each component behaves.

Lets take some sample code to understand each component. We have not included any message components in the VF.

<apex:page controller="MyRegisterCon2" sidebar="false" docType="HTML-5.0"   >

<apex:form >
  <apex:pageBlock >
  <apex:pageblockSection columns="1" >
  <apex:inputtext value="{!FirstName}" label="First Name"  />
  <apex:inputtext value="{!LastName}" label="Last Name" />
  <apex:input value="{!Jdate}" label="DOB" type="date" />
  <apex:inputtext value="{!Phone}" label="Phone"  id="phone"/>
  </apex:pageblockSection>
  <apex:pageBlockButtons >
  <apex:commandButton value="submit" action="{!save}" />
  </apex:pageBlockButtons>
  </apex:pageBlock>
  </apex:form>
</apex:page>

public with sharing class MyRegisterCon2 {

    public Date Jdate { get; set; }
   
    public Integer Phone { get; set; }
    
    public String LastName { get; set; }

    public String FirstName { get; set; }
    
    public PageReference save() {
    
        return null;
    }
       

}





Though phone and DOB are not strings it is not showing any errors when you click on submit.


<apex:message>:

This  component is used to display warning or error message for a specific component.

Change visualforce to following code.

<apex:page controller="MyRegisterCon2" sidebar="false" docType="HTML-5.0"   >

<apex:form >
  <apex:pageBlock >
  <apex:pageblockSection columns="1" >
  <apex:message for="phone" />
  <apex:inputtext value="{!FirstName}" label="First Name"  />
  <apex:inputtext value="{!LastName}" label="Last Name" />
  <apex:input value="{!Jdate}" label="DOB" type="date" id="dob" />
  <apex:inputtext value="{!Phone}" label="Phone"  id="phone"  />

  </apex:pageblockSection>
  <apex:pageBlockButtons >
  <apex:commandButton value="submit" action="{!save}" />
  </apex:pageBlockButtons>
  </apex:pageBlock>
  </apex:form>

</apex:page>







In above code I have included  <apex:message for="phone" /> . Though we have given text for DOB and Phone fields the message is shown for only specific component.
 i.e. Phone.

<apex:messages>

Include above code in VF page it will display all the messages . If we observe styling was not applied to the messages.

<apex:page controller="MyRegisterCon2" sidebar="false" docType="HTML-5.0"   >

<apex:form >
  <apex:pageBlock >
  <apex:pageblockSection columns="1" >
  <apex:messages />
  <apex:inputtext value="{!FirstName}" label="First Name"  />
  <apex:inputtext value="{!LastName}" label="Last Name" />
  <apex:input value="{!Jdate}" label="DOB" type="date" id="dob" />
  <apex:inputtext value="{!Phone}" label="Phone"  id="phone"  />
  </apex:pageblockSection>
  <apex:pageBlockButtons >
  <apex:commandButton value="submit" action="{!save}" />
  </apex:pageBlockButtons>
  </apex:pageBlock>
  </apex:form>

</apex:page>





<apex:pageMessages>

The  above component provides the SF styling for the messages. 

<apex:page controller="MyRegisterCon2" sidebar="false" docType="HTML-5.0"   >

<apex:form >
  <apex:pageBlock >
  <apex:pageblockSection columns="1" >
  <apex:pageMessages />
  <apex:inputtext value="{!FirstName}" label="First Name"  />
  <apex:inputtext value="{!LastName}" label="Last Name" />
  <apex:input value="{!Jdate}" label="DOB" type="date" id="dob" />
  <apex:inputtext value="{!Phone}" label="Phone"  id="phone"  />
  </apex:pageblockSection>
  <apex:pageBlockButtons >
  <apex:commandButton value="submit" action="{!save}" />
  </apex:pageBlockButtons>
  </apex:pageBlock>
  </apex:form>

</apex:page>





<apex:pageMessage>

This component is used to dispaly custom messages with severity error,warning etc.  in the VF page.

<apex:page controller="MyRegisterCon2" sidebar="false" docType="HTML-5.0"   >

<apex:form >
  <apex:pageBlock >
  <apex:pageblockSection columns="1" >
  <apex:pageMessage summary="This is page message"  severity="warning" strength="3" />
  <apex:inputtext value="{!FirstName}" label="First Name"  />
  <apex:inputtext value="{!LastName}" label="Last Name" />
  <apex:input value="{!Jdate}" label="DOB" type="date" id="dob" />
  <apex:inputtext value="{!Phone}" label="Phone"  id="phone"  />
  </apex:pageblockSection>
  <apex:pageBlockButtons >
  <apex:commandButton value="submit" action="{!save}" />
  </apex:pageBlockButtons>
  </apex:pageBlock>
  </apex:form>

</apex:page>




Hope this will be helpful to understand differrent messages in VF.

Thanks,
Naveen.

Tuesday, April 7, 2015

How to generate weekly report and sent it as a attachment in mail in Salesforce?

Problem:
 We can generate reports as per our requirement using standard Report Builder Functionality.
With report builder we can create reports ,run reports and even we can schedule and send through mails.


The problem is we can get report as body of the mail not as attachment .

 

Solution:

With  Apex Code we can send reports as attchemnts. This is ideal, because you can have the code run weekly, scheduled inside your salesforce.com instance. No visualforce necessary in this case, because the results could be emailed or submitted to an HTTP server (not FTP, because Apex Code can't yet do that).
  Below is the sample code which gets content from Report and prepares an attachment to send through mail.
  It implements System.Schedulable interface so we can schedule this class to run weekly or monthly.
 

global class Accounts_Weekly_Report implements System.Schedulable {
    global void execute(SchedulableContext sc) {
        ApexPages.PageReference report = new ApexPages.PageReference('/00OF0000006WD6L?csv=1');
        Messaging.EmailFileAttachment attachment = new Messaging.EmailFileAttachment();
        attachment.setFileName('Accounts_Weekly_Report.csv');
        attachment.setBody(report.getContent());
        attachment.setContentType('text/csv');
        Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage();
        message.setFileAttachments(new Messaging.EmailFileAttachment[] { attachment } );
        message.setSubject('Accounts Weekly Report');
        message.setPlainTextBody('The report is attached.');
        message.setToAddresses( new String[] { 'abc1@test.com','abc2@test.com' } );
        message.setCcAddresses(new String[] { 'abc3@test.com'});
        Messaging.sendEmail( new Messaging.SingleEmailMessage[] { message } );
        
    }
    }


Thanks,
Naveen.
www.autorabit.com 

Monday, March 9, 2015

Validation before the deployment with ANT

We can do deployment from one org to another using eclipse or Ant migration tool.  To validate the deployments we have an option Validate deployment in eclipse. Where it does a  deployment check and never actually saves to the server. We can do same by using Ant using  A task called deployCodeCheckOnly.

   <target name="deployCodeCheckOnly">
      <sf:deploy username="${sf.username}" password="${sf.password}" serverurl="${sf.serverurl}" maxPoll="${sf.maxPoll}" deployRoot="retrieveUnpackaged" checkOnly="true"/>
    </target>

Thanks,
Naveen.
http://www.autorabit.com/

New enhancements/Features related to Developement/APIs in Salesforce Spring 15

As we know new Salesforce Spring 15 (i.e. Version 33) is  came into live from mid of February 2015. Following are the main features or enhancements related to Developement/APIs in Salesforce Spring 15.
 
   Force.com development and API Enhancements:
  1.   Deploy to production without running all tests with Quick Deploy. You can now deploy components to production by skipping the execution of all Apex tests for components that have been validated within the last four days.
  2. New Visualforce attributes for Visualforce map component displays locations more precisely.
  3. The URLFOR function has been optimized for use with attachments in Visualforce.
  4.  Submit more batch jobs with Apex Flex Queue.
  5.   Use asynchronous callouts to make long-running requests from a Visualforce page to an external Web service and process responses with callback methods (aka, Long-Running Callouts).
  6.   Setup test data for an entire test class and then access them in every test method in the test class using the new @testSetup annotation.
  7.      Queueable Apex can now chain a job to another job an unlimited number of times.
  8.       The Apex callout size limit for requests and responses has been increased to the heap size limit.
  9.       List Apex classes and triggers with a Tooling API endpoint.
  10.    If you use ConnectApi (Chatter in Apex) there are an extremely large number of enhancements to checkout.
  11.  There is a number of new and modified Apex classes and interfaces so see the docs for details.
  12.     API v33.0 has a large number of new and changed objects for you to pore over. The REST API now supports insert/update of BLOB data plus CORS support!
  13.     The Streaming API now supports generic streaming for events that aren’t tied to Salesforce data changes.
  14.    The Tooling API adds SOSL support and a few new objects and new fields on existing objects.
  15.     For ISV there are also a number of enhancements that will make you happy and your jobs easier.
 Thanks,
Naveen.

Sunday, February 8, 2015

What is the difference between Insert and Database.Insert in salesforce.


Insert
If we use the DML statement (insert), then in bulk operation if error occurs, the execution will stop. In that case Apex code throws an error and none of the record is inserted to the database.


Database.Insert
If DML database methods (Database.insert) used, then if error occurs the remaining records will be inserted / updated means partial DML operation will be done. The only record throwing an error will not be inserted / updated.

So you should use Database.insert in any bulk dml operation if you are not monitoring the code properly

Regards,
Naveen,
http://www.autorabit.com/.