Sunday 31 August 2014

Migrate Images in the Rich Text Area Field in Salesforce

Introduction

In this post I am going to walk you thru,

 - How to migrate images in the rich text area from one instance (org) to another instance (org).

As you already aware, we cannot migrate images inside rich text area field as part of data migration. We have to do some workarounds for migrating all the images to destination organization and make it available as usual in the rich text are fields. This post will give you enough information to achieve the same.

STEP 1: Store rich text area images as documents in the source instance.

Write a controller class which retrieves all the images in the rich text area, convert it to document and store it. Remember that you cannot use batch class for doing this as we cannot use getContent() in batch class.
NOTES:
 - You have to combine “RichTextAreaFieldData.csv” & “ContentReference.csv” files from your Data Export and store the result set data on source instance in a custom object or custom setting (let us assume object name as RTA_Image__c). This is the critical input for your image conversion class.
 - Make sure you are storing the Content Reference Id in the Description field of the document.
Sample Code
string strUrl = 'https://c.ap1.content.force.com/servlet/rtaImage?';
string strFolderId = 'FoLdERidToStore';
string strQuery = 'select Id, Content_Reference_Id__c, Record_Id__c, Field_Id__c, Image_Name__c, Type__c, Owner_Id__c from RTA_Image__c' + (Test.isRunningTest() ? ' limit 5' : '');
list<Document> lstDocuments = new list<Document>();
for(RTA_Image__c rtaImage : Database.query(strQuery)) {
    PageReference pageRef = new PageReference(strUrl + 'eid=' + rtaImage.Record_Id__c + '&feoid=' + rtaImage.Field_Id__c + '&refid=' + rtaImage.Content_Reference_Id__c);
    Document doc = new Document();
    doc.Name = rtaImage.Image_Name__c;
    doc.Type = rtaImage.Type__c;
    if(Test.isRunningTest()) {
        doc.Body = Blob.valueOf('This is sample text.');
    }
    else {
        doc.Body = pageRef.getContent();
    }
    doc.FolderId = strFolderId;
    doc.Description = Id.valueOf(rtaImage.Content_Reference_Id__c);
    lstDocuments.add(doc);
}
if(!lstDocuments.isEmpty()) {
    insert lstDocuments;
}

STEP 2: Export all the documents which are stored in that specific folder using Force.com Migration Tool.

STEP 3: Import all the exported documents to target instance using Force.com Migration Tool.

STEP 4: Export all the documents (which you have imported in the previous step) using data loader. You can export Id and Description fields alone. Description and Id fields are critical inputs for next step.

STEP 5: Store the Description and Id values which are exported from the target instance into custom setting or custom object in source instance (you can use the same object or custom setting which is created in Step 1).

STEP 6: Write a batch class in source instance which iterate all the rich text area fields, identify the images, replace the image URL and store the result set in a separate object (let us assume object name as RTA_Value__c). This process should be repeated for all the objects which have rich text area fields on it.

NOTES: 
 - You cannot write this batch apex in target instance because salesforce is automatically replacing the invalid image URL’s inside the rich text area field with empty image URL while importing.
Sample Code
map<string, Configurations__c> mapDocs = Configurations__c.getAll();
string srcUrl = mapDocs.get('RTA Image URL').Value__c;
string destUrl = mapDocs.get('RTA Image Dest URL').Value__c;
list<RTA_Value__c> lstRTAValues = new list<RTA_Value__c>();
string strRTAFields = strFields.replace('Id, ', '');
for(sObject obj : scope) {
    for(string fieldName : strRTAFields.split(', ')) {
        string srcRTAValue = String.valueOf(obj.get(fieldName));
        if(!String.isEmpty(srcRTAValue)) {
            while(srcRTAValue.contains(srcUrl)) {
                string oldUrl = srcRTAValue.substring(srcRTAValue.indexOf(srcUrl), srcRTAValue.indexOf('"', srcRTAValue.indexOf(srcUrl)));
                string contentRefId = oldUrl.substring(oldUrl.indexOf('refid=') + 6).replace('">', '');
                string newUrl = destUrl + 'file=' + mapDocs.get(contentRefId).Value__c;
                srcRTAValue = srcRTAValue.replace(oldUrl, newUrl);
            }
            if(srcRTAValue != String.valueOf(obj.get(fieldName))) {
                RTA_Value__c rtaValue = new RTA_Value__c();
                rtaValue.PMO_Id__c = Id.valueOf(String.valueOf(obj.get('Id')));
                rtaValue.Object_Name__c = strObject;
                rtaValue.Field_Name__c = fieldName;
                rtaValue.Old_Value__c = String.valueOf(obj.get(fieldName));
                rtaValue.New_Value__c = srcRTAValue;
                lstRTAValues.add(rtaValue);
            }
        }
    }
}
if(!lstRTAValues.isEmpty()) {
    insert lstRTAValues;
}

STEP 7: Export the values stored in RTA_Value__c object and prepare a csv file for importing. You can use Object_Name__c and Field_Name__c fields for preparing the csv file.

STEP 8: Import the new rich text area field values to the corresponding objects in the target instance.

Conclusion

You should be able to migrate and retain the images inside rich text area field by following above steps in a proper way. Some important facts of this workaround are,
 - Rich text area images are stored in documents in the target instance and it is served from there for rich text area. Usually salesforce stores rich text area field images in a separate server and serves from there.
 - This workaround considers images in the rich text area only and not any other components like links which points to source instance document / location.

Thursday 11 October 2012

Email alerts to dynamic recipients for Case Comments using Standard Workflow Email Alert in Salesforce

Introduction:

In my previous post we have seen how we can send email alerts to static recipients for case comments using standard worklfow email alert "http://salesforcefox.blogspot.in/2012/10/email-alerts-for-case-comments-using.html". 

In this post I am going to walk you thru
   - how to send email alerts to dynamic recipients for case comments using standard salesforce feature.


Field Creation:

Create a long text area field in Case object. I would suggest to give the name as "Recent Case Comment" since value in this field is always going to be latest case comment of this case.
 

Create Workflow to Populate "Recent Case Comment" Field:

Step 1: Create workflow rule for Case Comment object. Evaluation criteria would be "created".

Screen shot for reference


Step 2: Create New Field Update action for the created workflow rule. Field to Update = Case objects "Recent Case Comment" field and Value formula = CommentBody.

Screen shot for reference

Step 3: Activate the workflow.


Create Workflow to Send Email Alerts:

Step 1: As a first step create Email Template for sending email alert.

Screen shot for reference




Step 2: Create workflow rule for Case object. Evaluation criteria would be "created or edited".


Screen shot for reference



Step 3: Create New Email Alert action for the created workflow rule. Choose the Email Template which we have created in Step 1. Unless like in the previous post, here recipients could be any persons who are related to that case. For example recipient could be Related Contact / Related User / Related Lead / Account Owner / Email Field (in case object) / Case Owner / Customer Portal User / User / Roles / Public Groups.


Screen shot for reference




Step 4: Activate the workflow rule.


Testing Results:


Once we are done with the above steps we are ready to receive case comment notification dynamically. Below is my testing results. I have highlighted the merge fields results for easy understanding.

Screen shot for reference









Email alerts for Case Comments using Standard Workfow Email Alert in Salesforce

Introduction: 

In this post we are going to see how to send email alerts for Case Comments using standard workflow email alerts.

As most of the salesforce developer's knows
   - Though we can create Workflow Rules for Case Comments object, there is no option for choosing Case Comments object and its fields while creating Email Templates. So they will think that there is no option for sending email alerts for Case Comments using standard Workflow Email Alerts but this is not true.

Even though Case Comments fields are not available in the "Available Merge Fields" section in the Email Templates, we can manually enter Case Comments fields (in the standard merge fields formats) in the email templates, sf will automatically replace all these fields properly and send email alert to the specified email ids.

Create Email Template:

Create sample email template for case comment notification. Assume the email template name as "Case Comment Notification Template". While creating email template you can specify case comment fields using the standard merge field format {!CaseComment.XXXX}. For example, if you would like to display the comment body then merge field would be {!CaseComment.CommentBody}, like wise we can access all case comment fields.
One more cool thing is we can also specify the Case fields. e.g: {!Case.CaseNumber}, {!Case.Subject} and so on... 
Screen shot for reference
 

Create Workflow Rule and Email Alert:

Step 1: Create workflow rule for Case Comment object. Workflow Evaluation Criteria would be "Created".
Step 2: Add "New Email Alert" workflow action to the created workflow rule. While creating new email alert choose already created email template "Case Comment Notification Template" and choose relevant recipients. 
Note: Recipient could be any User / Customer Portal User / Public Groups / Roles.
Step 3: Activate the workflow rule.
Screen shot for reference

Testing Results:

Once we are done with the above steps we are ready to receive case comment notification. Below is my testing results. I have highlighted the merge fields results for easy understanding.

Screen shot for reference


Disadvantages:

As we all know here disadvantage is "We cannot send email alerts to dynamic recipients". Since recipients are chosen statically i.e either User / Public Group / Roles, there is no way to send email alerts dynamically to any user related to Case and so on... 
So the scope of this facility is limited as of now, but if salesforce starts supporting field creation in Case Comment then we will be all set with this feature. 
Yes, I know until then we need some workaround for solving this issue which I will be walking you thru in my next post "Email alerts to dynamic recipients for Case Comments using Standard Workflow Email Alert in Salesforce".