• Eric_Arizona
  • NEWBIE
  • 40 Points
  • Member since 2014

  • Chatter
    Feed
  • 0
    Best Answers
  • 1
    Likes Received
  • 0
    Likes Given
  • 6
    Questions
  • 4
    Replies
I need some help figuring out the best way to call salesforce.com/merge/accmergewizard.jsp? from a visual force page. The merge tool is very cool but limited to First Last name. I've taken the awesome code from Jeff Douglas apex-search-with-checkbox-results blog and modified it to search my person-acounts by email.
step 1
User-added image

User-added image
public class AccountMergeSearchController {

// -----------------------------------------------------------------------
// public class CategorySearchController {
// copied from Jeff Douglas code
// see http://blog.jeffdouglas.com/2009/01/13/apex-search-with-checkbox-results/

    // the results from the search. do not init the results or a blank rows show up initially on page load
    public List<AmsWrapper> searchResults {get;set;}
    // the categories that were checked/selected.
    public List<AmsWrapper> selectedAccounts {
        get {
            if (selectedAccounts == null) selectedAccounts = new List<AmsWrapper>();
            return selectedAccounts;
        }
        set;
    }      

    // the text in the search box
    public string searchText {
        get {
            if (searchText == null) searchText = 'email'; // prefill the serach box for ease of use
            return searchText;
        }
        set;
    } 

    // constructor
    public AccountMergeSearchController() {}

    // fired when the search button is clicked
    public PageReference search() {

        if (searchResults == null) {
            searchResults = new List<AmsWrapper>(); // init the list if it is null
        } else {
            searchResults.clear(); // clear out the current results if they exist
        }
        // Note: you could have achieved the same results as above by just using:
        // searchResults = new List<AmsWrapper>();

        // dynamic soql for fun
        String qry = 'SELECT a.Name, a.Id, a.CreatedDate, a.PersonEmail, a.City_St_Zip__c, a.Any_CI__c, a.Control_NumberFormulafield__c, a.Secondary_Name__c ' +
                      'FROM Account a ' +
                      'WHERE a.PersonEmail LIKE \'%'+searchText+'%\' ' +
                      'ORDER BY a.CreatedDate';
        // may need to modify for governor limits??
        for(Account a : Database.query(qry)) {
            // create a new wrapper by passing it the category in the constructor
            AmsWrapper aw = new AmsWrapper(a);
            // add the wrapper to the results
            searchResults.add(aw);
        }
        return null;
    }   

    public PageReference next() {

        // clear out the currently selected categories
        selectedAccounts.clear();

        // add the selected categories to a new List
        for (AmsWrapper aw : searchResults) {
            if (aw.checked)
                selectedAccounts.add(new AmsWrapper(aw.acct));
        }

        // ensure they selected at least one category or show an error message.
        if (selectedAccounts.size() > 1) {
            return Page.AmsResultVF;
            // *** My test code HERE ***
          // 1 PageReference pr = New PageReference('/merge/accmergewizard.jsp?' + 'goNext=+Next+' + '&cid=001e000000C1FwE' + '&cid=001e000000CqmcV');
          // 2 pr.getParameters().put('goNext','+Next+');
          // 2 pr.getParameters().put('cid','001200000012346');
          // 2 return pr;
            
        } else {
            ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Please select at least TWO Accounts.'));
            return null;
        }       

    }       

    // fired when the back button is clicked
    public PageReference back() {
        return Page.AccountMergeSearchVF;
    }       

}
 
public class AmsWrapper { 
   
// Account Merge Search Wrapper

    public Boolean checked{ get; set;}
    public Account acct { get; set;}

    public AmsWrapper(){
        acct = new Account();
        checked = false;
    }

    public AmsWrapper(Account a){
        acct = a;
        checked = false;
    }

}
 
<apex:page controller="AccountMergeSearchController">
    <apex:form >
        <apex:pageBlock mode="edit" id="block">

            <apex:pageBlockButtons location="bottom">
                <apex:commandButton action="{!next}" value="Merge Accounts" disabled="{!ISNULL(searchResults)}"/>
            </apex:pageBlockButtons>
            <apex:pageMessages />

            <apex:pageBlockSection >
                <apex:pageBlockSectionItem >
                    <apex:outputLabel for="searchText">Search for Accounts</apex:outputLabel>
                    <apex:panelGroup >
                    <apex:inputText id="searchText" value="{!searchText}"/>
                    <!-- We could have rerendered just the resultsBlock below but we want the  -->
                    <!-- 'Merge' button to update also so that it is clickable. -->
                    <apex:commandButton value="Search" action="{!search}" rerender="block" status="status"/>
                    </apex:panelGroup>
                </apex:pageBlockSectionItem>
            </apex:pageBlockSection>

            <apex:actionStatus id="status" startText="Searching... please wait..."/>
            <apex:pageBlockSection title="Search Results" id="resultsBlock" columns="1">
                <apex:pageBlockTable value="{!searchResults}" var="a" rendered="{!NOT(ISNULL(searchResults))}">
                    <apex:column width="25px">
                        <apex:inputCheckbox value="{!a.checked}"/>
                    </apex:column>
                    <apex:column value="{!a.acct.Name}"/>
                    <apex:column value="{!a.acct.Id}"/>
                    <apex:column value="{!a.acct.Secondary_Name__c}" headerValue="Secondary"/>
                    <apex:column value="{!a.acct.PersonEmail}"/>
                    <apex:column value="{!a.acct.Control_NumberFormulafield__c}" headerValue="Control #"/>
                    <apex:column value="{!a.acct.City_St_Zip__c}"/>
                    <apex:column value="{!a.acct.CreatedDate}"/>
                    <apex:column value="{!a.acct.Any_CI__c}"/>
                </apex:pageBlockTable>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>
 
<apex:page controller="AccountMergeSearchController">
    <apex:form >
        <apex:pageBlock >

            <apex:pageBlockButtons >
                <apex:commandButton action="{!back}" value="Back"/>
            </apex:pageBlockButtons>
            <apex:pageMessages />

            <apex:pageBlockSection title="You Selected" columns="1">
                <apex:pageBlockTable value="{!selectedAccounts}" var="a">
                    <apex:column value="{!a.Acct.Name}"/>
                </apex:pageBlockTable>
                <apex:outputLink value="https://cs15.salesforce.com/merge/accmergewizard.jsp?goNext=+Next+&cid=001e000000C1FwE&cid=001e000000CqmcV">Click to Merge</apex:outputLink>
            </apex:pageBlockSection>           
        </apex:pageBlock>
    </apex:form>
</apex:page>

 
New Apex developer, old IBM AS400 RPG programmer. Don't yet understand OO looking to see if I'm going about things okay.
Not sure when I should be calling Static vs Instantiated methods.

Trigger on Booking Object AKA Community_Visit
trigger BookingTrigger on Community_Visit__c (before insert, before update, after insert, after update) {
	
	BookingTriggerHandler handler = new BookingTriggerHandler();
	
    if(Trigger.isInsert){  
        if(Trigger.isBefore){
            handler.onBeforeInsert(Trigger.new);
        }
        if(Trigger.isAfter){
        	   handler.onAfterInsert(Trigger.new);
        }
    }
    
    if(Trigger.isUpdate){
        if(Trigger.isBefore){
            handler.onBeforeUpdate(Trigger.old,Trigger.new,Trigger.oldMap);
        }
        if(Trigger.isAfter){
            handler.onAfterUpdate(Trigger.old,Trigger.new);
        }
    }
}
Booking Trigger Handler
/**************************************************************************************
Class Name              : BookingTriggerHandler
Created By              : Eric
Created on              : 08/04/2014
Description             : Booking ( Community_Visit__C ) Trigger Handler 
Version                 : 1.0
***************************************************************************************/

public with sharing class BookingTriggerHandler {
    
    /* When  Created */
    
    public void onBeforeInsert(list<Community_Visit__c> newCV){
        System.debug('BK before insert'+newCV);
        List<Community_Visit__c> CVtoEm = new List<Community_Visit__c>();
        Set<Id> CVAccts = new Set<Id>();
        Set<Id> CVUsers = new Set<Id>();
        for (Community_Visit__c CV : newCV){
            if(CV.Type__c == '3 Day' && CV.Total_Billable_Amount__c > 0){
                CV.Type_of_Funds__c = 'With Funds';
            } else {
                CV.Type_of_Funds__c = 'With Out Funds';
            }
            if(CV.Type__c == '3 Day' 
               && CV.Status__c == 'Pending Billing'
               && CV.Date__c > Date.today().addDays(30)){
                   CVtoEm.add(CV);
               }
        }
        if(CVtoEm.size()>0){
            BookingEmailToCustNewAppt.sendCustEmail(CVtoEM);
            //bookingEmailToCustNewAppt be = new bookingEmailToCustNewAppt();
            //be.SendCustEmail(CVtoEm);
        }
    }
    
    public void onAfterInsert(list<Community_Visit__c> newCV){
        System.debug('BK after insert'+newCV);
        for (Community_Visit__c CV : newCV){
            if(CV.Type__c == '3 Day' && CV.Total_Billable_Amount__c > 0){
                DNCTransactions.addExceptionforBooking(CV.Account__c,CV);
            }
        }
    }
    
    
    /* When  Updated */
    
    public void onBeforeUpdate(list<Community_Visit__c> oldCV, list<Community_Visit__c> newCV, map<Id,Community_Visit__c> MoldCV){
        System.debug('BK before update'+newCV);
        List<Community_Visit__c> CVtoEm = new List<Community_Visit__c>();
        for (Community_Visit__c CV : newCV){
            if(CV.Type__c == '3 Day' && CV.Total_Billable_Amount__c > 0){
                CV.Type_of_Funds__c = 'With Funds';
            } else {
                CV.Type_of_Funds__c = 'With Out Funds';
            }
            if(CV.Type__c == '3 Day' 
               && CV.Status__c == 'Pending Billing' 
               && CV.Status__c != MoldCV.get(CV.Id).Status__c
               && CV.Date__c > Date.today().addDays(30)){
                   CVtoEm.add(CV);
               }
        }
        System.debug('CVtoEm='+CVtoEm+' size='+CVtoEm.size());
        if(CVtoEm.size()>0){
            BookingEmailToCustNewAppt.sendCustEmail(CVtoEM);
        }
    }
    
    public void onAfterUpdate(list<Community_Visit__c> oldCV, list<Community_Visit__c> newCV){
        System.debug('BK after update'+newCV);
        for (Community_Visit__c CV : newCV){
            if(CV.Type__c == '3 Day' && CV.Total_Billable_Amount__c > 0){
                system.debug('the fund value is '+CV.Type_of_Funds__c);
                DNCTransactions.addExceptionforBooking(CV.Account__c,CV);
            }
        }
    }
    
}
BookingEmailToCustNewAppt
/*******************************************************
ClassName:     BookingEmailToCustNewAppt
Created By:    Eric
Created Date:  08/01/2014
Description:   Send Appt email to customer 
********************************************************/
public with sharing class BookingEmailToCustNewAppt {
    public static void SendCustEmail(list <Community_Visit__c> listCVs){
        System.debug('In SendCustEmail');
        
        // Step 0: Create a master list to hold the emails we'll send
        List<Messaging.SingleEmailMessage> mails = new List<Messaging.SingleEmailMessage>();
        Set<Id> CVAccts = new Set<Id>();
        Set<Id> CVUsers = new Set<Id>();
        for (Community_Visit__c CV : listCVs){
            CVAccts.add(CV.Account__c);
            CVUsers.add(CV.InsideSalesperson__c);
        }
        
        Map<Id,Account> AcctM = new Map<Id,Account>([SELECT Id, PersonEmail FROM Account WHERE Id IN :CVAccts]);
        System.debug('AcctM='+AcctM);
        Map<Id,User> UserM = new Map<Id,User>([SELECT Id, Name,Email,Signature FROM User WHERE Id IN :CVUsers]);
        System.debug('UserM='+UserM);
        
        for (Community_Visit__c CV : listCVs){
            
            System.debug('CV='+CV);
            
            datetime aDt = CV.Date__c;
            
            Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
            
            List<String> sendTo = new List<String>();
            if (CV.Alternate_Email__c != null) {
                sendTo.add(CV.Alternate_Email__c);
            } else {
                sendTo.add(AcctM.get(CV.Account__c).PersonEmail);
            }
            System.debug('sendTo=' +sendTo);
            mail.setToAddresses(sendTo);
            
            mail.setReplyTo(UserM.get(CV.InsideSalesperson__c).Email); 
            mail.setSenderDisplayName(UserM.get(CV.InsideSalesperson__c).Name);
            
            // List<String> BccTo = new List<String>();
            // BccTo.add(UserM.get(CV.InsideSalesperson__c).Email);
            // mail.setBccAddresses(BccTo);
            
            mail.setSubject('Confirmation of your Vist');
            String body = '<p>Dear ' +CV.First_Name__c+ ',</p>';
            
            body += '<p>Text</p>';
            
            body += '<p>More text.</p>';
            
            body += '<p>A dollar amount $' +CV.Total_Billable_Amount__c.SetScale(2)+ ' (includes tax) at that time. ';
            body += 'are scheduled to arrive on ' +aDt.format('EEEE, MMMM d, yyyy')+ '.';
            body += 'If you have any questions, please feel free to call the ' +CV.Community_Names__c+ ' sales office toll-free at ';
            body += '' +CV.Cmty_Phone__c+ '.</p>';
            
            body += '<br>Sincerely,';
            if (UserM.get(CV.InsideSalesperson__c).Signature <= ''){
                body += '<br><br>'+ UserM.get(CV.InsideSalesperson__c).Name+ '<br>';
                body += 'Inside Sales Consultant<br>';
            }
            
            mail.setHtmlBody(body);
            mails.add(mail);
        }
        
        System.debug('mails='+mails);
        try{
            Messaging.sendEmail(mails);
        } catch(exception ex1) {
            System.debug('ex1='+ex1);
            Messaging.SingleEmailMessage mail=new Messaging.SingleEmailMessage();
            String[] toAddresses = new String[] {'eric.@****.com'};
                mail.setToAddresses(toAddresses);
            mail.setReplyTo('eric@****.com');
            mail.setSenderDisplayName('Apex error message');
            mail.setSubject('Error from Org : ' + UserInfo.getOrganizationName());
            mail.setPlainTextBody(ex1.getMessage());
            Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
        }
        
    }
}



Trying to get an email address via User through an object called Community_Visit__c.
InsideSalesperson__c is a lookup(User) field in my custome object.

for (Community_Visit__c CV : listCVs){
      System.debug('cv.is='+cv.InsideSalesperson__c);
      System.debug('cv.is.email='+cv.InsideSalesperson__r.email);
      mail.setReplyTo(CV.InsideSalesperson__r.Email); mail.setSenderDisplayName(CV.InsideSalesperson__r.Name);
}

the above code returns the following debug info.
cv.is=005i0000000jo3XAAQ
cv.is.email=null

if I run this SOQL query  in developer console
SELECT InsideSalesperson__c,InsideSalesperson__r.email,InsideSalesperson__r.name from Community_Visit__c where account__c = '001e000000C1FwE'
it returns 

InsideSalesperson__c = 005i0000000jo3XAAQ
InsideSalesperson__r.Email = mary.k@emaiaddress.com
InsideSalesperson__r.Name = Mary K

so why is it returning null in apex ?
FYI this code is called from a trigger

thanks, Eric J
What determines how much data is shown after a Rest Request using HttpPost. My data being truncated. (, ...)

1
System.debug('Strg '+req.toString();
2
System.debug('my Rest Request '+req.params);

produces results as follows: see the ... in the examples below:

example one
reqRestRequest:[headers={Cache-Control=max-age=259200, CipherSuite=RC4-MD5 SSLv3 128-bits, Connection=keep-alive, Content-Type=application/x-www-form-urlencoded, Host=robson.secure.force.com, Referer=https://robson.secure.force.com/, User-Agent=ColdFusion, X-Salesforce-Forwarded-To=na1.salesforce.com, X-Salesforce-SIP=xx.xxx.xx.xxx}, httpMethod=POST, params={FormID=XXXXX, adid=texas, aid=1, areacode=xxx, campaign=777, email=myemail@gmail.com, next_url=http://www.robson.com/sem_v2/confirmation.cfm?wantDVD=0&dsd=15&display=&CFID=1234567&CFTOKEN=12345678, pginterest=on, postfix=1507, prefix=555, ...}, remoteAddress=xx.xxx.xx.xxxx, requestBody=Blob[0], requestURI=/sfwebtolead/Robson, resourcePath=/services/apexrest/*]


example two
FormID=FreeDVD, adid=internet, aid=, areacode=555, areasofinterest=, bst_tme=morning, campaign=485, control=0, ectrl=, email=name@emailaddress.com, ...


I believe the data/params in both cases is being truncated and appended with ...
I would like to return the full data so I can write it to a custom LOG file.
What determines how much data is show and where it stops and returns the ...

Thanks, Eric
 I would like to add a button in the Address section of the standard Account page that would call the smartyStreet app update the address. We already use SmartyStreet software for Address Verification. It is currently called only inside our account trigger handler when a new account is added or an address is modified. The problem is we have thousands of records that were not verified during initial Data Load. The current work around is to make an non address change change for example change address from 123 N 1st St to 123 N 1st Street and press Update. Hoping to do this with just a simple button press.
How do you create a test class over a utility class when the methods are pretty much all just passing parms back and forth? For example I have a method that gets passed a name field and the method just does some formatting like first letter upper case the rest of each word lower case, etc.  finally it passes the name back.
Since tests are all static.  
Thanks for the help.
 I would like to add a button in the Address section of the standard Account page that would call the smartyStreet app update the address. We already use SmartyStreet software for Address Verification. It is currently called only inside our account trigger handler when a new account is added or an address is modified. The problem is we have thousands of records that were not verified during initial Data Load. The current work around is to make an non address change change for example change address from 123 N 1st St to 123 N 1st Street and press Update. Hoping to do this with just a simple button press.
I need some help figuring out the best way to call salesforce.com/merge/accmergewizard.jsp? from a visual force page. The merge tool is very cool but limited to First Last name. I've taken the awesome code from Jeff Douglas apex-search-with-checkbox-results blog and modified it to search my person-acounts by email.
step 1
User-added image

User-added image
public class AccountMergeSearchController {

// -----------------------------------------------------------------------
// public class CategorySearchController {
// copied from Jeff Douglas code
// see http://blog.jeffdouglas.com/2009/01/13/apex-search-with-checkbox-results/

    // the results from the search. do not init the results or a blank rows show up initially on page load
    public List<AmsWrapper> searchResults {get;set;}
    // the categories that were checked/selected.
    public List<AmsWrapper> selectedAccounts {
        get {
            if (selectedAccounts == null) selectedAccounts = new List<AmsWrapper>();
            return selectedAccounts;
        }
        set;
    }      

    // the text in the search box
    public string searchText {
        get {
            if (searchText == null) searchText = 'email'; // prefill the serach box for ease of use
            return searchText;
        }
        set;
    } 

    // constructor
    public AccountMergeSearchController() {}

    // fired when the search button is clicked
    public PageReference search() {

        if (searchResults == null) {
            searchResults = new List<AmsWrapper>(); // init the list if it is null
        } else {
            searchResults.clear(); // clear out the current results if they exist
        }
        // Note: you could have achieved the same results as above by just using:
        // searchResults = new List<AmsWrapper>();

        // dynamic soql for fun
        String qry = 'SELECT a.Name, a.Id, a.CreatedDate, a.PersonEmail, a.City_St_Zip__c, a.Any_CI__c, a.Control_NumberFormulafield__c, a.Secondary_Name__c ' +
                      'FROM Account a ' +
                      'WHERE a.PersonEmail LIKE \'%'+searchText+'%\' ' +
                      'ORDER BY a.CreatedDate';
        // may need to modify for governor limits??
        for(Account a : Database.query(qry)) {
            // create a new wrapper by passing it the category in the constructor
            AmsWrapper aw = new AmsWrapper(a);
            // add the wrapper to the results
            searchResults.add(aw);
        }
        return null;
    }   

    public PageReference next() {

        // clear out the currently selected categories
        selectedAccounts.clear();

        // add the selected categories to a new List
        for (AmsWrapper aw : searchResults) {
            if (aw.checked)
                selectedAccounts.add(new AmsWrapper(aw.acct));
        }

        // ensure they selected at least one category or show an error message.
        if (selectedAccounts.size() > 1) {
            return Page.AmsResultVF;
            // *** My test code HERE ***
          // 1 PageReference pr = New PageReference('/merge/accmergewizard.jsp?' + 'goNext=+Next+' + '&cid=001e000000C1FwE' + '&cid=001e000000CqmcV');
          // 2 pr.getParameters().put('goNext','+Next+');
          // 2 pr.getParameters().put('cid','001200000012346');
          // 2 return pr;
            
        } else {
            ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,'Please select at least TWO Accounts.'));
            return null;
        }       

    }       

    // fired when the back button is clicked
    public PageReference back() {
        return Page.AccountMergeSearchVF;
    }       

}
 
public class AmsWrapper { 
   
// Account Merge Search Wrapper

    public Boolean checked{ get; set;}
    public Account acct { get; set;}

    public AmsWrapper(){
        acct = new Account();
        checked = false;
    }

    public AmsWrapper(Account a){
        acct = a;
        checked = false;
    }

}
 
<apex:page controller="AccountMergeSearchController">
    <apex:form >
        <apex:pageBlock mode="edit" id="block">

            <apex:pageBlockButtons location="bottom">
                <apex:commandButton action="{!next}" value="Merge Accounts" disabled="{!ISNULL(searchResults)}"/>
            </apex:pageBlockButtons>
            <apex:pageMessages />

            <apex:pageBlockSection >
                <apex:pageBlockSectionItem >
                    <apex:outputLabel for="searchText">Search for Accounts</apex:outputLabel>
                    <apex:panelGroup >
                    <apex:inputText id="searchText" value="{!searchText}"/>
                    <!-- We could have rerendered just the resultsBlock below but we want the  -->
                    <!-- 'Merge' button to update also so that it is clickable. -->
                    <apex:commandButton value="Search" action="{!search}" rerender="block" status="status"/>
                    </apex:panelGroup>
                </apex:pageBlockSectionItem>
            </apex:pageBlockSection>

            <apex:actionStatus id="status" startText="Searching... please wait..."/>
            <apex:pageBlockSection title="Search Results" id="resultsBlock" columns="1">
                <apex:pageBlockTable value="{!searchResults}" var="a" rendered="{!NOT(ISNULL(searchResults))}">
                    <apex:column width="25px">
                        <apex:inputCheckbox value="{!a.checked}"/>
                    </apex:column>
                    <apex:column value="{!a.acct.Name}"/>
                    <apex:column value="{!a.acct.Id}"/>
                    <apex:column value="{!a.acct.Secondary_Name__c}" headerValue="Secondary"/>
                    <apex:column value="{!a.acct.PersonEmail}"/>
                    <apex:column value="{!a.acct.Control_NumberFormulafield__c}" headerValue="Control #"/>
                    <apex:column value="{!a.acct.City_St_Zip__c}"/>
                    <apex:column value="{!a.acct.CreatedDate}"/>
                    <apex:column value="{!a.acct.Any_CI__c}"/>
                </apex:pageBlockTable>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>
 
<apex:page controller="AccountMergeSearchController">
    <apex:form >
        <apex:pageBlock >

            <apex:pageBlockButtons >
                <apex:commandButton action="{!back}" value="Back"/>
            </apex:pageBlockButtons>
            <apex:pageMessages />

            <apex:pageBlockSection title="You Selected" columns="1">
                <apex:pageBlockTable value="{!selectedAccounts}" var="a">
                    <apex:column value="{!a.Acct.Name}"/>
                </apex:pageBlockTable>
                <apex:outputLink value="https://cs15.salesforce.com/merge/accmergewizard.jsp?goNext=+Next+&cid=001e000000C1FwE&cid=001e000000CqmcV">Click to Merge</apex:outputLink>
            </apex:pageBlockSection>           
        </apex:pageBlock>
    </apex:form>
</apex:page>

 
Trying to get an email address via User through an object called Community_Visit__c.
InsideSalesperson__c is a lookup(User) field in my custome object.

for (Community_Visit__c CV : listCVs){
      System.debug('cv.is='+cv.InsideSalesperson__c);
      System.debug('cv.is.email='+cv.InsideSalesperson__r.email);
      mail.setReplyTo(CV.InsideSalesperson__r.Email); mail.setSenderDisplayName(CV.InsideSalesperson__r.Name);
}

the above code returns the following debug info.
cv.is=005i0000000jo3XAAQ
cv.is.email=null

if I run this SOQL query  in developer console
SELECT InsideSalesperson__c,InsideSalesperson__r.email,InsideSalesperson__r.name from Community_Visit__c where account__c = '001e000000C1FwE'
it returns 

InsideSalesperson__c = 005i0000000jo3XAAQ
InsideSalesperson__r.Email = mary.k@emaiaddress.com
InsideSalesperson__r.Name = Mary K

so why is it returning null in apex ?
FYI this code is called from a trigger

thanks, Eric J
How do you create a test class over a utility class when the methods are pretty much all just passing parms back and forth? For example I have a method that gets passed a name field and the method just does some formatting like first letter upper case the rest of each word lower case, etc.  finally it passes the name back.
Since tests are all static.  
Thanks for the help.