Thursday, April 17, 2014

Visualforce & Visual Workflow & Force.com Sites

Introduction

The true potential of  Visual Workflow or simply Flow is either not known to many or is often under estimated. But many are beginning to realize the versatility of Flows and are using them for many different purposes, ranging from case management applications to help agents gather only the required information, to surveys, assessment test, buttons that can close cases while sending emails, converted leads, lead de-duplication etc. Very interesting implementations of Flows are popping up everywhere. But please be careful, just because you can use a Flow to clean your data or close a case does not mean you should do it. Always use the KISS principle when developing applications and as a true "Salesforcedotcomer" always choose configuration over code. 
Today I would like to show you how amazingly simple it is to include your Flows in a Visualforce page and expose this to everyone on a Force.com site. Does that sound exciting? ... it does to me, so let's dive in.

Flows and Visualforce


I will assume here that you have already created a flow called "CustomerSurvey". Creating Flows will be the subject for a different day, but if you want to create a Flow now to try this out, please check out this article: Visual Workflow: Freedom of Choice

Including a flow in a Visualforce page is ridiculously easy in Salesforce. Create a simple Visualforce page that looks like this
 <apex:page sidebar="false" showHeader="false" standardStylesheets="false">  
   <flow:interview name="CustomerSurvey" />  
 </apex:page>  

As I said ridiculously easy. All you need is the interview component and set it to the API name of the Flow. That's it. For this Visualforce page we do not even need a controller or a controller extension. If you intend to expose this Visualforce page which contains the Flow on a Force.com site, branded according to your companies look-and-feel, you can set the standardStyleSheets, sidebar and showHeader Properties to false as done above. You can then apply your own style sheets directly to the page or to components of the Flow. Check out this page on how to style Flow components: Customizing a Flow's User Interface.
I have however made the experience that applying custom style sheets to Flows can be a pain in the place where the sun doesn't shine. The scripting involved can get quite heavy. This is especially true if you want to embed your brand new Force.com site which now holds your Flow into a website that has it's own unique styles. Normally you would do this using Iframes and have to mimic the styles of the website within your Visualforce and Flows ... jackkk.

So what if you what to pass parameters to your Flow?. Also ridiculously easy. You can use the param component like this:
 <apex:page sidebar="false" showHeader="false" standardStylesheets="false">  
   <flow:interview name="CustomerSurvey">  
        <apex:param name="lang" value="{!$CurrentPage.parameters.lang}" />   
   </flow:interview>  
 </apex:page>  

Still no controller or controller extension. But what if you wanted to do more complex stuff like aggregate information from different sources and make it available to the Flow?. Then you have to start thinking about adding a controller. For example, imagine instead of adding a "lang" parameter to the URL, we decided to dynamically determine the user's language depending on the Geo-Location. You will need to do this in a controller and then bind the value to the page such that the Flow can use it to show the Survey in the appropriate language.
 <apex:page controller="CustomerSurveyController" sidebar="false" showHeader="false" standardStylesheets="false">  
       <flow:interview name="CustomerSurvey" interview="{!surveyFlow}"/>  
        <apex:param name="lang" value="{!language}" />   
   </flow:interview>  
 </apex:page>  

You controller could look something like this
 public class CustomerSurveyController{  
      public Flow.Interview.CustomerSurvey surveyFlow { get; set; }  
      public String language { get; set; }  
      public CustomerSurveyController(){  
            myflow = new Flow.Interview.CustomerSurvey(new Map<String, Object>());  
            language = determineLanguageFromGeoLocation();  
      }  
      public String determineLanguageFromGeoLocation(){  
           String lang;  
           return lang;  
      }  
 }  

and your page like this:

Force.com Sites


Creating a force.com Site involves two things
- choosing and registering a domain and
- creating the site by specifying it's contents (Visualforce page) and it's sub domain.

When creating the site, your page could look like this:


Please visit this site on details of how to create sites Introduction to Sites


Conclusion


I hope you found this short and relatively straight forward article on Visualforce, Flows and Sites very useful. The results which in this case would be a Flow embedded in a Visualforce page and exposed using a Force.com Site could then be embedded into a public website using iframes.
As usual I encourage you to challenge the contents of this post, and add value to it by offering your thoughts, alternative solutions etc. I appreciate. God bless. 


Apex Email Validation

Introduction 


Email Validation is one of those things that have been around for as long as I can think, and Emails aren't going any where any time soon. So today I will show you how you can validate a bunch of Email addresses in Apex before sending out your emails. You can inform the user of any wrong email addresses and have them correct them before proceeding.

What is a valid Email address? 


The correct answer to this question is "Well it depends". The next question is probably "on what?". There has always been and there is still a long debate going on around this, at times to philosophical for my taste. I will not get into that here. All I can say is, be certain what you want your validation rules to cover and use simple regular expressions to cover them. Here is my favorite site on Regular Expressions. For the fanatics among you check this for guidance RFC 5322 - Address Specification.
What you definitely shouldn't do is try to invent a Reg Ex that covers everything - this is a fool's errand. I got slapped around a couple of times by Apex's "Regex too complicated" error. That said, let's move on to the real issue.

Apex


To send emails to a bunch of Users, you would normally pass a list of up to 100 email addresses to the  setToAddresses() method of a SingleEmailMessage() instance. Check out these post to see how your could let your users input email addresses: Add and remove email recipients dynamically & Building an email recipient list from pre-selected users

Before setting the email address list in your SingleEmailMessage instance, it is an excellent idea to validate your email address list. Use a function that looks like this:
 public List<String> validateEmailAddressPatternExample(List<String> emailAddresses){  
      List<String> wrongEmailAddresses = new List<String>();  
      String regEx = '^[a-zA-Z0-9._|\\\\%#~`=?&/$^*!}{+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}$';  
      try{  
           for(String email : emailAddresses){  
                if(!Pattern.matches(regEx, email)){  
                     wrongEmailAddresses.add(email);  
                }  
           }  
      } catch(Exception e){  
           wrongEmailAddresses.add('Error occured');  
      }  
      return wrongEmailAddresses;  
 }  

Here every single email address is matched against a Pattern which is compiled from the supplied Regular Expression.

Another way to do this will be to compile the Regular Expression into a pattern object and then create a Matcher for a single email and then use the Matcher's match() method to check if it is valid.
 public List<String> validateEmailAddressMatcherExample(List<String> emailAddresses){  
      List<String> wrongEmailAddresses = new List<String>();  
      String regEx = '^[a-zA-Z0-9._|\\\\%#~`=?&/$^*!}{+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}$';  
      Pattern emailPattern = Pattern.compile(regEx);  
      try{  
           for(String email : emailAddresses){  
                Matcher emailMatcher = emailPattern.matcher(email);  
                if(!emailMatcher.matches()){  
                     wrongEmailAddresses.add(email);  
                }  
           }  
      } catch(Exception e){  
           wrongEmailAddresses.add('Error occured');  
      }  
      return wrongEmailAddresses;  
 }  

Since we want to inform the User about the email addresses which are not valid, we gather them together in a list and return them to the calling function. In the calling function we could then check the list returned and inform the user that some email addresses are not valid.
 List<String> wrongEmailAddresses = this.validateEmailAddress(emailAddresses);  
 if(!wrongEmailAddresses.isEmpty()){  
      String errorMsg;  
      if(wrongEmailAddresses.size() > 1){  
           String wrongEmails = String.join(wrongEmailAddresses, ',');  
           errorMsg = 'The Opportunity Report was not distributed. Please correct the following Email addresses: ' + wrongEmails;  
           errorMsg += '<ul>';  
           for()  
      } else {  
           errorMsg = 'The Opportunity Report was not distributed. Please correct the following Email address: ' + wrongEmailAddresses[0];  
      }  
      Apexpages.Message msg = new Apexpages.Message(Apexpages.Severity.Error, errorMsg);  
      Apexpages.addMessage(msg);  
      return null;  
 }  






If only a single address is wrong, no problem, the error message is pretty basic. If many are wrong, the User gets all of them in one line as a comma separated list.



But a better way would probably be to list them one after another. This is definitely more readable. This is the improve code snippet:
 List<String> wrongEmailAddresses = this.validateEmailAddress(emailAddresses);  
 if(!wrongEmailAddresses.isEmpty()){  
      String errorMsg;  
      if(wrongEmailAddresses.size() > 1){  
           String wrongEmails = String.join(wrongEmailAddresses, ',');  
           errorMsg = 'The Opportunity Report was not distributed. Please correct the following Email addresses: ';  
           errorMsg += '<ul>';  
           for(String emailAdd : wrongEmailAddresses){  
                errorMsg += '<li>' + emailAdd + '</li>';  
           }  
           errorMsg += '</ul>';  
      } else {  
           errorMsg = 'The Opportunity Report was not distributed. Please correct the following Email address: ' + wrongEmailAddresses[0];  
      }  
      Apexpages.Message msg = new Apexpages.Message(Apexpages.Severity.Error, errorMsg);  
      Apexpages.addMessage(msg);  
      return null;  
 }  

Visualforce

Your visualforce needs to include the pageMessages tag for the error messages to be displayed. If you use HTML in your Apex code like we did above to present the wrong email addresses in the list, you need to set the escape attribute of the pageMessage component to false.
 <apex:outputPanel id="pageMessages">  
      <apex:pageMessages escape="false" />  
 </apex:outputPanel>  

Notice the the pageMessage component is wrapped in an outputPanel component. This is a common technique used which gives us the possibility to be able to refresh only the pageMessage component when our call to the controller return.
 <apex:commandButton value="Distribute Opportunity Report Now" action="{!distribute}" rerender="pageMessages"></apex:commandButton>  

Conlusion


I hope you enjoyed reading this post. To make it more useful to others viewing it in the future, i challenge you to challenge it's contents and offer alternatives. Thanks and God bless

Saturday, April 12, 2014

Add and remove email recipients dynamically

Introduction


This is the second post in a series of 5 post revolving around sending an Opportunity Report as an email attachment to members of the Opportunity team on a weekly basis. Here is the first post: Building an email recipient list from pre-selected users

Problem Definition


In addition to selecting members of the opportunity team to get the weekly opportunity report, Sales Managers might want to send the email report to recipients who are not part of the sales team. They would like these extra recipients to be remembered  so they don't have to type them each week. They would also like to be able to remove them from the list if they should not get the report for  a particular week. 

Solution


If additional recipients exist, show each of them in a text box and next to the text box a "Remove Recipient" button. Also add a "Add Recipient" button. Clicking on the button should add a new text box - "Remove Recipient" button pair above it. Additional recipients will be stored on a custom field on the Opportunity object. For this example, I will use the same field mentioned in the post above.

Your end result could look like this;



Apex


In the Controller Extension we need the following;
- a wrapper class to encapsulate the additional recipients
- a property to bind our wrapper class list to our page
- a list of previously added additional recipients 
- functions to add and remove additional recipients

Wrapper Class


A wrapper class is a class that "wraps" or "encapsulates" the functionality of another or component with the intention of adding a layer of indirection and abstraction. 

 public class AddionalRecipients{  
      public String emailAddress { get; set; }  
      public Integer position { get; set; }  
      public String textClass { get; set; }  
      public AddionalRecipients(String email, Integer recCount, String txtClass){  
           position = recCount;  
           emailAddress = email;  
           textClass = txtClass;  
      }  
 }  



Our wrapper class has a property which binds an additional email address and wraps it together with it's position in the list. This will be needed when removing an email address from the list. For cosmetic reasons we also have a textClass property which will be used to differentiate between an actual email address and a default text used in the input text field. More on this later.

Property


 public List<AddionalRecipients> additionalRecipients { get; set;}  

Previously added recipients



This is a tricky one. Imagine that we have a field Email_Recipients__c on Opportunity which holds comma separated email addresses of selected opportunity team members (from the post mentioned in the Introduction) plus additional recipients added using the functionality we are building here. Trick question - how would you separate them?. Think about it at check out the function "buildListOfAdditionalRecipients" at the end of this section. 
After this point you should end up with a list, that holds email addresses of additional recipients from the previous week. Now wrap them using our wrapper class as follows;

 private void buildAdditionalRecipientsList(List<String> additionalEmails){  
      this.additionalRecipients = new List<AddionalRecipients>();  
      for(Integer i= 0; i < additionalEmails.size(); i++){  
           if(additionalEmails[i].equals('Type new recipient Email!')){  
                this.additionalRecipients.add(new AddionalRecipients(additionalEmails[i], i, 'defaultText'));       
           } else {  
                this.additionalRecipients.add(new AddionalRecipients(additionalEmails[i], i, 'realText'));  
           }  
      }  
 }  

Here we use the traditional "for" loop because we want to know the exact index of the email in our list. If the user decides to remove the a user from the list, this will ensure that we are removing the right user from the list.

"defaultText" is the class name which specifies the style applied to the default text which is "Type new recipient Email!". If we are dealing with an email address that was previously used we want to apply a different style "realText". 

There is a good reason for putting the wrapping of additional emails in a function of its own. Will explain in a minute. Read on.

Add recipient action


Clicking on the "Add Recipient" Button calls an action which looks like this;

 public void addRecipient(){  
      List<String> additionalEmails = new List<String>();  
      for(AddionalRecipients ar : this.additionalRecipients){  
           additionalEmails.add(ar.emailAddress);  
      }  
      additionalEmails.add('Type new recipient Email!');  
      this.buildAdditionalRecipientsList(additionalEmails);  
 }  

First we "unwrap" the list of additional recipients, add a new one with the default text and wrap them again by passing them to the "buildAdditionalRecipientsList" function. Pretty straight forward.

Remove recipient action


To remove an additional recipient from the list, the following action is called;

 public void removeRecipient(){  
      List<String> additionalEmails = new List<String>();  
      this.additionalRecipients.remove(rowToRemove);  
      for(AddionalRecipients ar : this.additionalRecipients){  
           additionalEmails.add(ar.emailAddress);  
      }  
      this.buildAdditionalRecipientsList(additionalEmails);  
 }  

A property "rowToRemove" is used to communicate the index of the entry to remove from the list. 
public Integer rowToRemove { get; set; } 

First the entry is removed, then the list of remaining emails is unwrap and wrapped again using the wrapper class. Trick question - so why is it necessary to unwrap? why not just leave the list as it is?. 
The reason is because we always want to have a clean fresh list every time we remove an entry from the list. Avoiding to do so will lead to an "Index Out of Bound Exception", when you try to remove an entry from the list, whose index does no longer exist because the List reduced in size when a recipient was previously removed. My clinical approach is therefore to always bind a fresh list each time a recipient is removed from the list. 

Finally going back to the question of how to separate, the team members email addresses from the additional recipients added through the "Add recipient" Button, a possible solution could look like this

 public void buildListOfAdditionalRecipients(){  
      List<String> emailAddress = new List<String>();  
      if(this.opportunity.Email_Recipients__c != null){  
           emailAddress = new List<String>(this.opportunity.Email_Recipients__c.split(','));  
      }  
      List<String> additionalEmails = new List<String>();  
      Map<String, String> teamMemberMap = new Map<String, String>();  
      for(TeamMembers tm : this.OpportunityTeam){  
           teamMemberMap.put(tm.teamMember.User.Email, tm.teamMember.User.Email);  
      }  
      for(String emailAdd : emailAddress){  
           if(!teamMemberMap.containsKey(emailAdd)){  
                additionalEmails.add(emailAdd);  
           }  
      }  
      if(additionalEmails.isEmpty()){  
           additionalEmails.add('Type new recipient Email!');  
      }  
      this.buildAdditionalRecipientsList(additionalEmails);  
 }  

Visualforce


In Visualforce we will loop through the additional recipients list, and build the input text fields and the remove button as follows:

 <apex:outputPanel id="additionalRecipients">  
      <apex:repeat value="{!additionalRecipients}" var="recipient">  
           <apex:inputText id="addedEmail" value="{!recipient['emailAddress']}" styleClass="additionalRecipients {!recipient['textClass']}" onfocus="removeDefaultText('{!$Component.addedEmail}');" />  
           <apex:commandButton value="Remove Recipient" action="{!removeRecipient}" rerender="additionalRecipients">  
           <apex:param name="rowToBeRemoved" value="{!recipient['position']}" assignTo="{!rowToRemove}" />  
           </apex:commandButton>  
           <br />  
      </apex:repeat>  
 </apex:outputPanel>  

Notice the "assignTo" attribute which assigns the index of the additional recipient to be removed to the "rowToRemove" property. Also note the "rerender" attribute. Having the Controller Extension bind a fresh list every  time an additional recipient is removed from the list works thanks to this attribute. This attributes refreshes the div element identified by "additionalRecipients" ensuring that what we see on the page is consistent with what is in the Controller Extension.

Also note the "removeDefaultText" javaScript function which removes the default text once we click into the text field.

 <script type="text/javascript">  
      function hasClass(element, cls){  
           return(' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;  
      }  
      function removeDefaultText(idOfAddedField){  
           var element = document.getElementById(idOfAddedField);   
           if(element.value == 'Type new recipient Email!'){  
                element.value = '';  
                if(hasClass(element, 'defaultText')){  
                     element.className = element.className.replace(' defaultText', ' realText');  
                }  
           }  
      }  
 </script>  

Finally the "Add Recipient" Button could look like this;

 <apex:pageBlockSectionItem >  
      <apex:commandButton value="Add Recipient" action="{!addRecipient}" rerender="additionalRecipients" />  
 </apex:pageBlockSectionItem>  

Conclusion

I hope this post was helpful to you.One last trick quest though -  how would you handle issues that might arise from users trying to send emails with default text in the input text fields, or empty input text fields because they clicked in them and type nothing? Would you simply ignore these or would you notify the user to remove unnecessary fields etc.?. These and more will be part of the next Post.
Finally, please challenge the contents of this post, add value to it in the comments if you can, so that it can help others viewing it in the future. God bless

Building an email recipient list from pre-selected users

This is the first post in the series of 5 post that revolve around sending an Opportunity Report as an email attachment to members of the Opportunity Team on a weekly basis.  


Problem Definition


Sales Managers need to send an opportunity report every week to members of the opportunity team. A custom button on the opportunity page layout is used for this. Selected email addresses should be remembered so that they can be pre-selected the following week.

Solution


Build a Visualforce table which will enable selecting and deselecting of opportunity team members from a list. Use a custom field on opportunity to hold a String of comma separated values. These will be parsed in Apex and used to pre-select entries in the table when it is displayed.

Your end result could look like this







Apex


You need 4 things in this order;
- a wrapper class which holds your table entries
- a property to bind your wrapper class list to the page
- a list of opportunity team members, thier emails, names etc.
- a list of previously selected recipients

Wrapper Class


A wrapper class is a class that "wraps" or "encapsulates" the functionality of another or component with the intention of adding a layer of indirection and abstraction. 

 public class TeamMembers{  
      public OpportunityTeamMember teamMember { get; set; }  
      public Boolean sendEmail { get; set;}  
      public TeamMembers(OpportunityTeamMember member, Boolean selected){  
           teamMember = member;  
           sendEmail = selected;  
      }  
 }  

Our Wrapper class is very simple and straight forward. It wraps the opportunity team member and adds a binary value which determines if the team member is selected to receive the email or not.

Property


 public List<TeamMembers> OpportunityTeam { get; set; }  

Opportunity Team


 List<OpportunityTeamMember> members = new List<OpportunityTeamMember>([SELECT id, User.Email, User.Name, TeamMemberRole, OpportunityAccessLevel FROM OpportunityTeamMember WHERE OpportunityId =: this.opportunity.id]);  

this.opportunity is opportunity whose opportunity report we want to send out. Could be set in the Constructor using the Standard Opportunity Controller as follows;

 this.opportunity = (Opportunity)stdController.getRecord();  

Previously Selected Recipients


 List<String> emailAddress = new List<String>(this.opportunity.Email_Recipients__c.split(','));  

This will give you a list of all team members who received the mail the previous week

Since you will not need to use "Email_Recipients__c" on the page, you need to tell the Standard Controller to fetch it along with the other fields by adding the following to the constructor;

 stdController.addFields(new List<String>{'Email_Recipients__c'});  

Apex Summary


To summarize, here is what an Apex function which merges all the above parts together could look like

 public void buildListOfEmailRecipients(){  
      this.OpportunityTeam = new List<TeamMembers>();  
      List<String> emailAddress = new List<String>();  
      if(this.opportunity.Email_Recipients__c != null){  
           emailAddress = new List<String>(this.opportunity.Email_Recipients__c.split(','));  
      }  
      Map<String, String> teamMemberMap = new Map<String, String>();  
      for(String mailadd : emailAddress){  
           teamMemberMap.put(mailadd, mailadd);  
      }  
      List<OpportunityTeamMember> members = new List<OpportunityTeamMember>([SELECT id, User.Email, User.Name, TeamMemberRole, OpportunityAccessLevel FROM OpportunityTeamMember WHERE OpportunityId =: this.opportunity.id]);  
      for(OpportunityTeamMember otm : members){  
           if(teamMemberMap.containsKey(otm.User.Email)){  
                this.OpportunityTeam.add(new TeamMembers(otm, true));  
           } else {  
                this.OpportunityTeam.add(new TeamMembers(otm, false));  
           }  
      }  
 }  

Visualforce


Most of the work has been done by the Controller, so displaying the table on Visualforce is a peaice of cake. Begin be sending the Standing Controller and Extension. Could look something like this;

 <apex:page StandardController="Opportunity" extensions="OpportunityEmailOnClosedCtr" sidebar="false" title="Send Email to \'{!Opportunity.Name} \' opportuinty team">  

Then Build the actual table which will could look like this;

 <apex:pageBlockSection title="Select Recipients from Opportunity Team and specify additional Recipients">  
      <apex:pageBlockSectionItem >  
           <apex:outputLabel value="Select Recipients from Opportunity Team" />  
      </apex:pageBlockSectionItem>  
      <apex:pageBlockSectionItem >  
           <apex:outputPanel ></apex:outputPanel>  
      </apex:pageBlockSectionItem>  
      <apex:PageBlockSectionItem rendered="{!OpportunityTeam.size > 0}">  
           <apex:pageBlockTable value="{!OpportunityTeam}" var="record" styleClass="sameWidth">  
                <apex:column headerValue="Slected">  
                     <apex:inputCheckbox value="{!record['sendEmail']}" />  
                </apex:column>  
                <apex:column headerValue="User Name">  
                     <apex:outputText value="{!record['teamMember'].User.Name}" />  
                </apex:column>  
                <apex:column headerValue="Email">  
                     <apex:outputText value="{!record['teamMember'].User.Email}" />  
                </apex:column>  
                <apex:column headerValue="Team Member Role">  
                     <apex:outputText value="{!record['teamMember'].TeamMemberRole}" />  
                </apex:column>  
           </apex:pageBlockTable>  
      </apex:PageBlockSectionItem>  
 </apex:pageBlockSection>  

The key to letting users select and deselect recipients is the inputCheckbox Component which uses the binary "sendMail" property of the wrapper class to keep track of which recipients are currently selected.


Finally in the Controller Extension, build a list or email recipients like this;
 List<String> emailAddresses = new List<String>();  
 for(TeamMembers tm : this.OpportunityTeam){  
      if(tm.sendEmail) {  
           emailAddresses.add(tm.teamMember.User.Email);  
      }  
 }  

Conlcusion


I hope this post was helpful to you. Watch out for related post which will handle topics such as dynamically adding and removing email recipients, sending emails with Visualforce PDF attachments, email validation and proper error handling etc.
Finally, please challenge the contents of this post, add value to it in the comments if you can, so that it can help others viewing it in the future. God bless