Saturday, 27 February 2016

Sending an email notification to Admin whenever a field is created or deleted for a custom object in salesforce

S.No Component
1 Create New Object
Singular Label: ObjectsExistingFieldsInfo
Plural Label: ObjectsExistingFieldsInfos
Object Name: ObjectsExistingFieldsInfo
Standard Field
Field Label: ObjectsExistingFieldsInfo
Data Type: Auto Number
Display Format: ObjInfo-{000}
2 Create New Field
Object Name: ObjectsExistingFieldsInfo
Field Label: Field API Name
Field Name: Field_API_Name
Data Type: Text (255)
3 Create New Field
Object Name: ObjectsExistingFieldsInfo
Field Label: Fields Count
Field Name: Fields_Count
Data Type: Number (18,0)
4 Create New Field
Object Name: ObjectsExistingFieldsInfo
Field Label: Fields Info
Field Name: Fields_Info
Data Type: Long Text Area
   global class FieldsValidator implements Database.Batchable<Sobject> {
    global Database.queryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator('select name, fields_info__c, fields_count__c from ObjectsExistingFieldsInfo__c');
    }
    global void execute(Database.BatchableContext bc, List<SObject> sobjLst) {
        String[] types = new String[]{'Account','Contact'};
        String emailBody = '';
        // Make the describe call
        Schema.DescribeSobjectResult[] results = Schema.describeSObjects(types);
        Map<String,List<Field>> objFieldsDesMap = new Map<String,List<Field>>();
        // For each returned result, get some info
        for(Schema.DescribeSobjectResult res : results) {
            Map<String, Schema.SObjectField> objectFields = res.fields.getMap();
            for(Schema.SObjectField fDes : objectFields.values()) {
                if(fDes.getDescribe().isCustom()) {
                    system.debug(fDes.getDescribe().getName()+'@@@'+fDes.getDescribe().getType());
                    String fieldAPIName = String.valueOf(fDes.getDescribe().getName());
                    String fieldDataType = String.valueOf(fDes.getDescribe().getType());
                    if(objFieldsDesMap.containsKey(res.getName())) {
                        objFieldsDesMap.get(res.getName()).add(new Field(fieldAPIName,fieldDataType));
                    }
                    else {
                        objFieldsDesMap.put(res.getName(),new List<Field>{new Field(fieldAPIName,fieldDataType)});
                    }
                }       
            }
        }
        Map<String, ObjectsExistingFieldsInfo__c> objectInfoMap = new Map<String, ObjectsExistingFieldsInfo__c>();
        for(ObjectsExistingFieldsInfo__c objInfo : [select Field_API_Name__c , Fields_Count__c, Fields_Info__c from 
        ObjectsExistingFieldsInfo__c where Field_API_Name__c in: types]) {
            objectInfoMap.put(objInfo.Field_API_Name__c,objInfo);
        }
        for(String type : types) {
            if(objectInfoMap.get(type).fields_count__c == null) {
                objectInfoMap.get(type).fields_count__c = objFieldsDesMap.get(type).size();
                objectInfoMap.get(type).fields_info__c = JSON.serialize(objFieldsDesMap.get(type));
            }
            else {
                System.debug('entering to else condition...');
                System.debug('entering to for loop..');
                List<Field> exstingFields = new List<Field>();
                List<Field> newFields = new List<Field>();
                Map<String,Field> bkupexstingFields = new Map<String,Field>();
                Map<String,Field> bkupnewFields = new Map<String,Field>();
                exstingFields = (List<Field>)JSON.deserialize(objectInfoMap.get(type).fields_info__c, List<Field>.class);
                System.debug('exstingFields: '+exstingFields);
                newFields.addAll(objFieldsDesMap.get(type));
                System.debug('objFieldsDesMap: '+objFieldsDesMap);
                System.debug('newFields: '+newFields);
                for(Field f : exstingFields) {
                    bkupexstingFields.put(f.apiName,f);
                }
                for(Field f : newFields) {
                    bkupnewFields.put(f.apiName,f);
                }
                for(Field f : exstingFields) {
                    bkupnewFields.remove(f.apiName);
                }
                for(Field f : newFields) {
                    bkupexstingFields.remove(f.apiName);
                }
                System.debug(bkupnewFields+'@@@'+bkupexstingFields);
                emailBody += type + ' : ';
                //for new fields
                for(Field f :bkupnewFields.values()) {
                    emailBody += f.apiName + ' with datatype '+f.dataType+' is newly created.'; 
                }
                objectInfoMap.get(type).fields_count__c = objFieldsDesMap.get(type).size();
                objectInfoMap.get(type).fields_info__c = JSON.serialize(objFieldsDesMap.get(type));
            }
        }
        /*** Sending Email ***/
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        mail.setToAddresses(new List<String>{system.label.Dev_Admin});
        mail.setSubject('Fields Update');
        mail.setPlainTextBody(emailBody);
        update objectInfoMap.values();
        Messaging.sendEmail(new Messaging.SingleEmailMessage[]{mail});
    }
    global void finish(Database.BatchableContext bc) {
    } 
    public class Field {
        String apiName, dataType;
        public Field(String apiName, String dataType) {
            this.apiName = apiName;
            this.dataType = dataType;
        }
    }
}
  
Notes-
  • We cannot create trigger on 'Object' or 'Field'.
  • Alternative is creating a Batch Class and schedule it as per the requirement.
  • To store the history of the fields we can user either list custom settings or custom object.
  • List Custom Settings is not supporting Text Area Long.
  • To store the history of the fields we need Text Area Long (255 character for text area data type is not sufficient.) field which is possible with the custom object.

14 comments:

  1. I had executed above code in my developer instance without any errors but i didn't get mail notification when field is create and field is delete.. please help me

    ReplyDelete
    Replies
    1. 1. Please populate your email address in 'system.label.Dev_Admin'.
      2. Execute once (you don't receive email).
      3. 2nd time please create/delete a field and execute one more time.
      4. If your email address is valid you should get an email.

      Delete
    2. This comment has been removed by the author.

      Delete
    3. I populated my email even then I didn't receive any email. How is this batch apex getting triggered first of all?

      Delete
  2. Great work. good scenario ... thank you very much.

    ReplyDelete
  3. Some interesting information are provided. But i need a brief explanation, provided samples are most useful for us.


    Salesforce Training in Chennai

    ReplyDelete

  4. Your posts is really helpful for me.Thanks for your wonderful post.It is really very helpful for us and I have gathered some important information from this blog. so keep sharing..

    Salesforce training in chennai

    ReplyDelete
  5. great presentation for email notifications which helps to gain more ideas.always keep sharing like these nice informative

    Salesforce Training in Chennai

    ReplyDelete
  6. With regards to various promoting alternatives, email advertising has assumed control as the main showcasing methodology and additionally a financially savvy arrangement.list of non profit organizations

    ReplyDelete
  7. your post vry helpful i m fresher
    when i m trying this code i m getting this errorError "Error: Compile Error: unexpected token: '@' at line 74 column 52" actually i m replced mailid in place of "system.label.Dev_Admin" if i did not replace i m getting this error "Error Error: Compile Error: Invalid external string name: dev_admin at line 74 column 46
    "

    ReplyDelete
  8. please i m waiting your response i hope i will get ASAP
    THANK YOU

    ReplyDelete


  9. Hai Author, Very Good informative blog post,
    Thanks for Sharing

    ReplyDelete