• Damon Hedgspeth
  • NEWBIE
  • 20 Points
  • Member since 2014

  • Chatter
    Feed
  • 0
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 4
    Questions
  • 5
    Replies
I have a invoicing app that tracks incoming invoices each month.  I would like to find out if any invoices are missing.

parent object is 'Service", "Invoice is a child".

The service record contains a numeric value of the day of the month that the invoice is usually due. 
Ideally, I would have a scheduled apex run nightly to check that an invoice record exists for each month since the Service was created. It could store the results in a field on the parent record (Missing_Invoices).

Service - (created 12-10/2015 , Invoice Due Day = 30
Invoice 1-23-16
Invoice 2-24-16
Invoice 4-17-16

The above example would update the missing_invoices field with "Invoice for March is missing".

A start on effinciently coding this would be greatly appreciated. 
I have a trigger on lead convert that creates a record in a managed package app.  When I run my test code, i get the following error: "Methods defined as TestMethod do not support Web service callouts". I have tried the httpmock code and istestrunning.  What am I missing?

Here is my trigger
trigger LeadConvert on Lead (after Insert,after update) {
   String recordTypeName = 'ID Lead Record Type'; // <-- Change this to your record type name
  
  Map<String,Schema.RecordTypeInfo> rtMapByName = Schema.SObjectType.Lead.getRecordTypeInfosByName();
  Schema.RecordTypeInfo rtInfo =  rtMapByName.get(recordTypeName);
  id recordTypeId = rtInfo.getRecordTypeId();
 if(!test.isrunningtest()) {
 For(Lead o : Trigger.New){
 If(o.RecordTypeId == recordTypeId){
 
  // no bulk processing; will only run from the UI
  if (Trigger.new.size() == 1) {

    if (Trigger.old[0].isConverted == false && Trigger.new[0].isConverted == true) {

      // if a new account was created
      if (Trigger.new[0].ConvertedAccountId != null) {

        // update the converted account with some text from the lead
        Account a = [Select a.Id, a.Description From Account a Where a.Id = :Trigger.new[0].ConvertedAccountId];
        a.Description = Trigger.new[0].Name;
        update a;

      }          

      // if a new contact was created
      if (Trigger.new[0].ConvertedContactId != null) {

        // update the converted contact with some text from the lead
        Contact c = [Select c.Id, c.Description, c.Name From Contact c Where c.Id = :Trigger.new[0].ConvertedContactId];
        c.Description = Trigger.new[0].Name;
        update c;
         
If(o.Create_Apttus_Proposal__c == True) {
        // insert a custom object associated with the contact
       
        Apttus_Proposal__Proposal__c obj = new Apttus_Proposal__Proposal__c();
        obj.Apttus_Proposal__Proposal_Name__c = c.Name;
        obj.Apttus_Proposal__Description__c = c.Description;
        obj.Apttus_Proposal__Account__c = Trigger.new[0].ConvertedAccountId;
        obj.Due_to_Funder__c = Date.today().addDays(+60);
        obj.Program__c = Trigger.new[0].Program__c;
        obj.Proposal_Reviewer_list__c = Trigger.new[0].Proposal_Reviewer_list__c;
        obj.Total_Proposal_Value__c = 1;
        obj.Apttus_Proposal__ExpectedStartDate__c = Date.today().addDays(+60);
        obj.Apttus_Proposal__ExpectedEndDate__c = Date.today().addDays(+365);
        obj.Account_Contact__c = Trigger.new[0].ConvertedContactId;
        obj.Lead_Id__c = c.id;
        obj.Proposal_Status__c = 'Awaiting RFP';
        insert obj;
}}{
      }

     

   } }

  }     

}
}
}
Here is my test code:
 
@isTest
public class LeadConvertTest {
   
    static testMethod void insertNewLead() {

        Lead newLead = new Lead();
        newLead.LastName = 'Lee';
        newLead.FirstName = 'James';
       newLead.Company = 'TestTrigger';
       newLead.Program__c = 'Assessment & Standards Development Services';
       newLead.Proposal_Reviewer_list__c = 'Aida Walqui';
       newLead.Create_Apttus_Proposal__c = True;

        insert newLead;
       
     test.startTest();
      Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator());
      

        Database.LeadConvert lc = new Database.LeadConvert();
       lc.setLeadId(newLead.id);

        
        

       LeadStatus convertStatus = [Select Id, MasterLabel from LeadStatus where IsConverted=true limit 1];
//lc.setConvertedStatus(convertStatus.MasterLabel);
lc.setConvertedStatus('Qualified');


       Database.LeadConvertResult lcr = Database.convertLead(lc);
        
        System.assert(lcr.isSuccess());

      test.stopTest();
    }

}


 
I've created an email template that will be sent to Accounts payable once an Invoice (custom object) has been approved.  In the email, I would like to show the full approval history for that invoice. including when it was submitted, and any rejections and subsequent approval.

My problem is, I can not seem to pull the dates/times in any order that makes since.    See code - notice that the Dates and Status areUser-added image out of order.
<messaging:emailTemplate subject="A new IS Invoice has been approved." recipientType="User" relatedToType="Bill_Item__c">
 <messaging:htmlEmailBody >

    <html>
    <head>
  
    <script>
         var people, asc1 = 1,
            asc2 = 1,
            asc3 = 1;
        window.onload = function () {
            people = document.getElementById("people");
           var peps = people;
peps.reverse();
        }

        function sortTable(){
    var tbl = document.getElementById("caltbl").tBodies[0];
    var store = [];
    for(var i=0, len=tbl.rows.length; i<len; i++){
        var row = tbl.rows[i];
        var sortnr = parseFloat(row.cells[0].textContent || row.cells[0].innerText);
        if(!isNaN(sortnr)) store.push([sortnr, row]);
    }
    store.sort(function(x,y){
        return x[0] - y[0];
    });
    for(var i=0, len=store.length; i<len; i++){
        tbl.appendChild(store[i][1]);
    }
    store = null;
}
        
        </script>

</head>
      <body onload="sortTable()">
        

        <STYLE type="text/css">
        
        
   
        #DIV_Top{font-size: 24px; font-weight: Bold;  padding: 0 0 0 10px; margin: 0; background-color: #add0c8; color: #ffffff;}
#Top_Text {font-size: 18px; font-face: arial; color:#ea896a}
#Top_Text0 {font-size: 18px; font-face: arial; color:#000000}
#Print{border: solid #CCCCCC; border-width: 1;background-color: #add0c8; width: 100px; }
#Print a:link { color: #ffffff;font-size: 14px; font-weight: bold;}
#Print a:visited { color: #ffffff;font-size: 14px;font-weight: bold; }
#Print a:hover { color: #ffffff; font-size: 14px;font-weight: bold;}
#Print a:active { color: #ffffff; font-size: 14px;font-weight: bold;}


.myButton {
    -moz-box-shadow:inset 0px 1px 3px 0px #91b8b3;
    -webkit-box-shadow:inset 0px 1px 3px 0px #91b8b3;
    box-shadow:inset 0px 1px 3px 0px #91b8b3;
    background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #768d87), color-stop(1, #6c7c7c));
    background:-moz-linear-gradient(top, #768d87 5%, #6c7c7c 100%);
    background:-webkit-linear-gradient(top, #768d87 5%, #6c7c7c 100%);
    background:-o-linear-gradient(top, #768d87 5%, #6c7c7c 100%);
    background:-ms-linear-gradient(top, #768d87 5%, #6c7c7c 100%);
    background:linear-gradient(to bottom, #768d87 5%, #6c7c7c 100%);
    filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#768d87', endColorstr='#6c7c7c',GradientType=0);
    background-color:#768d87;
    -moz-border-radius:5px;
    -webkit-border-radius:5px;
    border-radius:5px;
    border:1px solid #566963;
    display:inline-block;
    cursor:pointer;
    color:#ffffff !important;
    font-family:Arial;
    font-size:15px;
    font-weight:bold;
    padding:11px 23px;
    text-decoration:none;
    text-shadow:0px -1px 0px #2b665e;
   
}
.myButton:hover {
    background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #6c7c7c), color-stop(1, #768d87));
    background:-moz-linear-gradient(top, #6c7c7c 5%, #768d87 100%);
    background:-webkit-linear-gradient(top, #6c7c7c 5%, #768d87 100%);
    background:-o-linear-gradient(top, #6c7c7c 5%, #768d87 100%);
    background:-ms-linear-gradient(top, #6c7c7c 5%, #768d87 100%);
    background:linear-gradient(to bottom, #6c7c7c 5%, #768d87 100%);
    filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#6c7c7c', endColorstr='#768d87',GradientType=0);
    background-color:#6c7c7c;
     color:#ffffff !important;
}
.myButton:active {
    position:relative;
    top:1px;
      color:#ffffff !important;
}
.myButton:a {
    position:relative;
    top:1px;
 color:#ffffff !important;
}
.myButton:visited {
    position:relative;
    top:1px;
      color:#ffffff !important;
}
           TH.blue{font-size: 14px; font-face: arial;color: #ffffff; background: #34b0cd; 
               border-width: 2;  text-align: left} 
          TH.green {font-size: 14px; font-face: arial;color: #ffffff; background: #add0c8; 
               border-width: 2;  text-align: left} 
           TH.orange {font-size: 14px; font-face: arial;color: #ffffff; background: #ea896a; 
               border-width: 2;  text-align: left} 
               
          TD  {font-size: 14px; font-face: verdana;border: solid #Cdcdcd; border-width: 1;  } 
          TABLE {border: solid #CCCCCC; border-width: 0; }
          
TR.blue:nth-child(even) {color: #12547d}

TR.green  {color: #529384}
TR.orange  {color: #ea896a}
          TR {border: solid #CCCCCC; border-width: 1; padding: 0px;}
          
        </STYLE>
        <apex:variable var="count" value="{!0}" /> 
            
<apex:repeat var="cc" value="{!relatedTo.Bill_Payments__r}">

     <apex:outputPanel layout="none" rendered="{!cc.Allotment_User_Id__c != '-Select-'}">
   <apex:variable var="count" value="{!count+1}"/>
     </apex:outputPanel>
</apex:repeat>
        <font face="arial" size="3" color="#534e4e">
           <div id="Logo">
           </div>
           <div id="DIV_Top">
            <p>&#10004; &nbsp; Invoice Approved</p>
           </div>
           <div id="Top_Text0">
           <apex:outputText value="{!IF(count=0  ,"","**New Process**")}"/>
           </div>
            <p />
            
 
  
   
    
   
            
            The invoice related to {!relatedTo.Vendor_Account__r.Request_Type__c} <a href="  {!relatedTo.Vendor_Account__r.PO_Link__c}">{!relatedTo.Vendor_Account__r.Purchase_Order__c}</a> has been approved. <br />
            Please print this page and the associated Invoice for your records. <a href="{!relatedTo.Box_Share_Link__c}" class="myButton">Print Invoice</a>
           <p />
              <div id="Top_Text">
        Approval History
        </div>
          
<table border="0" cellspacing="0" cellpadding="5">
    <tr border-bottom="1"> 
               <th class="green">Approver</th>
               <th class="green">Date Approved</th>
               <th class="green">Status</th>
               <th class="green">Comments</th>
               </tr>
    <apex:repeat var="cx" value="{!relatedTo.ProcessSteps}">
        <tr class="green" >
           
             <td >{!cx.Actor.name}</td>
              <td><apex:outputText value="{0,date,MM'/'dd'/'yyyy}">
    <apex:param value="{!cx.ProcessInstance.CompletedDate}" /> 
</apex:outputText></td>
             
            <td>{!cx.StepStatus}</td>
           
            
           
         
            
          <td>{!cx.Comments}</td>
        </tr>
         
    </apex:repeat>                 
</table>
     <p />


     <p />
        <hr class="Top_Text"/>
             <div id="Top_Text">
             Invoice Information
             </div>       
          <table border="0" cellspacing="0" cellpadding="5">
            <tr > 
               <th class="blue">Service Name</th>
               <th class="blue">Account Number:</th>
               <th class="blue">Invoice Number:</th>
               <th class="blue">Invoice Date:</th>
               <th class="blue">Billing Cyle</th>
               <th class="blue">Month Processed:</th>
              <th class="blue">Total:</th>
             
            </tr>
                <tr class="blue">
                <td>
                <strong>{!relatedTo.Vendor_Account__r.Name}</strong>
                </td>
                <td>
                {!relatedTo.Account_Number__c}
                </td>
                 <td>
                {!relatedTo.Invoice_Number__c}
                </td>
                 <td>
               <apex:outputText value="{0,date,MM'/'dd'/'yyyy}">
    <apex:param value="{!relatedTo.Invoice_Date__c}" /> 
</apex:outputText>
                </td>
                 <td>
                <apex:outputText value="{0,date,MM'/'dd'/'yyyy}">
    <apex:param value="{!relatedTo.Billing_Cycle_Start__c}" /> 
</apex:outputText>  -  <apex:outputText value="{0,date,MM'/'dd'/'yyyy}">
    <apex:param value="{!relatedTo.Billing_Cycle_End__c}" /> 
</apex:outputText>
                </td>
                 <td>
                {!relatedTo.Month_Processed__c}
                </td>
                 <td>
                <strong>${!relatedTo.Total_Allotted_Amount__c}</strong>
                </td>
              
                   </tr>       
          </table>
          <p />
      
      
 <div id="Top_Text">
        Applied Cost Codes
                </div>
<table border="0" cellspacing="0" cellpadding="5">
   <tr border-bottom="1"> 
               <th class="orange">Cost Code</th>
               <th class="orange">User Id</th>
               <th class="orange">Amount Charged</th>
                              </tr> 
                         
<apex:repeat var="cc" value="{!relatedTo.Bill_Payments__r}">
    <tr class="grey"><td>
        {!IF(cc.Bill_Cost_Code__c = "[]","",SUBSTITUTE(SUBSTITUTE(cc.Bill_Cost_Code__c,"[", ""),"]","" ))}
        
       </td>
       <td>{!IF(cc.Allotment_User_Id__c = "-Select-","",  cc.Allotment_User_Id__c )}
     
       </td>
       <td style="text-align:right">${!cc.Allotment_Amount__c}</td></tr>
</apex:repeat>
     </table>


<p />
</font>

   </body>
    </html>
  </messaging:htmlEmailBody> 
<messaging:plainTextEmailBody >

The invoice related to PO# {!relatedTo.Vendor_Account__r.Purchase_Order__c} has been approved.

Please print this page and the associated Invoice for your records located here >> {!relatedTo.Box_Share_Link__c}

Invoice Information:

Service Name: {!relatedTo.Vendor_Account__r.Name}
Account Number: {!relatedTo.Account_Number__c}
Invoice Number:   {!relatedTo.Invoice_Number__c}
Invoice Date: <apex:outputText value="{0,date,MM'/'dd'/'yyyy}"><apex:param value="{!relatedTo.Invoice_Date__c}" /> </apex:outputText>
Billing Cyle:  <apex:outputText value="{0,date,MM'/'dd'/'yyyy}"><apex:param value="{!relatedTo.Billing_Cycle_Start__c}" /></apex:outputText>  -  <apex:outputText value="{0,date,MM'/'dd'/'yyyy}"><apex:param value="{!relatedTo.Billing_Cycle_End__c}" /> </apex:outputText>
Month Processed: {!relatedTo.Month_Processed__c}
Total: {!relatedTo.Total_Allotted_Amount__c}
             
Approval History:
 <apex:repeat var="cx" value="{!relatedTo.ProcessSteps}">        
{!cx.Actor.name}
<apex:outputText value="{0,date,MM'/'dd'/'yyyy}">
<apex:param value="{!cx.ProcessInstance.CompletedDate}" /> 
</apex:outputText>         
{!cx.StepStatus}
{!cx.Comments}
</apex:repeat>          
           
//history = SELECT Id, (SELECT Actor.name, CompletedDate, StepStatus)
FROM ProcessInstance           
           
Applied Cost Codes / User ID
                        
<apex:repeat var="cc" value="{!relatedTo.Bill_Payments__r}">
{!IF(cc.Bill_Cost_Code__c = "[]","",cc.Bill_Cost_Code__c)}{!IF(cc.Allotment_User_Id__c = "-Select-","",cc.Allotment_User_Id__c)}
</apex:repeat>             

</messaging:plainTextEmailBody>
</messaging:emailTemplate>

 
So, I've managed to learn a bit of apex. Now I really need a hand with testing the code so that I can move it to production.  Could someone please help me with the following?
public class multiAddCEx {

public Id cID = ApexPages.currentPage().getParameters().get('Id'); //grab the Vendor Bill ID
//Integer count = 0;
string num_name = '';
// Lookup against Available Cost Codes Junction Object
public List<SelectOption> costcodes {get; set;}
    public multiAddCEx ()
    {
        costcodes  = new List<SelectOption>() ;
          for(Cost_Code_Connection__c cc : [select Cost_Code_Junction2__r.Cost_Code_ID__c , Cost_Code_Percentage__c, id,name from Cost_Code_Connection__c where Cost_Code_Connection__c.Bill_Item_Junction__c =: cID order by Cost_Code_Junction2__r.Cost_Code_ID__c, Cost_Code_Percentage__c ])
        {
        costcodes.add(new SelectOption(cc.Cost_Code_Junction2__r.Cost_Code_ID__c +' - '+ cc.Cost_Code_Percentage__c +'%',cc.Cost_Code_Junction2__r.Cost_Code_ID__c +' - '+ cc.Cost_Code_Percentage__c +'%' )) ;
        }
  }
//Lookup to find User Intranet ID in User records
public List<SelectOption> intranetids {get; set;}
    {
        intranetids = new List<SelectOption>() ;
        intranetids.add(new SelectOption('-Select-','-Select-'));
        for(User ui : [select Intranet_ID__c , id, name, IsActive from User where IsActive = True order by Intranet_ID__c])
                {
if (ui.Intranet_ID__c != null){ 
num_name = ui.name;
        intranetids.add(new SelectOption(ui.Intranet_ID__c, ui.Intranet_ID__c +' - '+ num_name  )) ;
}
        }    
    }
List <Bill_Allotment__c> CExList;
public Id getID {get; set;}
public PageReference reset()  { //pull at most 8 expense records to show so we don't clutter up the page
CExList = [select name, Bill_Allotment__c.Phone_Number__c ,  Allotment_Amount__c, Bill_Allotment__c.Allotment_User_Id__c,  Bill_Allotment__c.Bill_Cost_Code__c  from Bill_Allotment__c where Bill_Item__c =: cID order by createddate limit 0 ];
return null; }
public List <Bill_Allotment__c> getCExs() {
 if(CExList == null) reset();
 return CExList;
  }
public void setAccounts(List <Bill_Allotment__c> cexs) {
   CExList = cexs;}
public PageReference save() {//upsert records on save
try{
       upsert CExList;
       ApexPages.Message myMsg = new ApexPages.message(ApexPages.Severity.Info, 'Records Saved Successfully'); //show confirmation message on save
ApexPages.addMessage(myMsg);
return null;   
       }
    catch(DmlException ex){
   
        ApexPages.addMessages(ex);
       }
    return null;       
}
//ApexPages.Message myMsg = new ApexPages.message(ApexPages.Severity.Info, 'Records Saved Successfully'); //show confirmation message on save
//ApexPages.addMessage(myMsg);
//return null;}
public PageReference cancel() {//close window without upsert
return null;
}
public PageReference add() {
//count++;
CExList.add(New Bill_Allotment__c(Bill_Item__c = cID)); //add records to Bill Items and associate with current Bill
return null; }
 //public Integer getCount() {
        //return count;
   // }
}
I have a trigger on lead convert that creates a record in a managed package app.  When I run my test code, i get the following error: "Methods defined as TestMethod do not support Web service callouts". I have tried the httpmock code and istestrunning.  What am I missing?

Here is my trigger
trigger LeadConvert on Lead (after Insert,after update) {
   String recordTypeName = 'ID Lead Record Type'; // <-- Change this to your record type name
  
  Map<String,Schema.RecordTypeInfo> rtMapByName = Schema.SObjectType.Lead.getRecordTypeInfosByName();
  Schema.RecordTypeInfo rtInfo =  rtMapByName.get(recordTypeName);
  id recordTypeId = rtInfo.getRecordTypeId();
 if(!test.isrunningtest()) {
 For(Lead o : Trigger.New){
 If(o.RecordTypeId == recordTypeId){
 
  // no bulk processing; will only run from the UI
  if (Trigger.new.size() == 1) {

    if (Trigger.old[0].isConverted == false && Trigger.new[0].isConverted == true) {

      // if a new account was created
      if (Trigger.new[0].ConvertedAccountId != null) {

        // update the converted account with some text from the lead
        Account a = [Select a.Id, a.Description From Account a Where a.Id = :Trigger.new[0].ConvertedAccountId];
        a.Description = Trigger.new[0].Name;
        update a;

      }          

      // if a new contact was created
      if (Trigger.new[0].ConvertedContactId != null) {

        // update the converted contact with some text from the lead
        Contact c = [Select c.Id, c.Description, c.Name From Contact c Where c.Id = :Trigger.new[0].ConvertedContactId];
        c.Description = Trigger.new[0].Name;
        update c;
         
If(o.Create_Apttus_Proposal__c == True) {
        // insert a custom object associated with the contact
       
        Apttus_Proposal__Proposal__c obj = new Apttus_Proposal__Proposal__c();
        obj.Apttus_Proposal__Proposal_Name__c = c.Name;
        obj.Apttus_Proposal__Description__c = c.Description;
        obj.Apttus_Proposal__Account__c = Trigger.new[0].ConvertedAccountId;
        obj.Due_to_Funder__c = Date.today().addDays(+60);
        obj.Program__c = Trigger.new[0].Program__c;
        obj.Proposal_Reviewer_list__c = Trigger.new[0].Proposal_Reviewer_list__c;
        obj.Total_Proposal_Value__c = 1;
        obj.Apttus_Proposal__ExpectedStartDate__c = Date.today().addDays(+60);
        obj.Apttus_Proposal__ExpectedEndDate__c = Date.today().addDays(+365);
        obj.Account_Contact__c = Trigger.new[0].ConvertedContactId;
        obj.Lead_Id__c = c.id;
        obj.Proposal_Status__c = 'Awaiting RFP';
        insert obj;
}}{
      }

     

   } }

  }     

}
}
}
Here is my test code:
 
@isTest
public class LeadConvertTest {
   
    static testMethod void insertNewLead() {

        Lead newLead = new Lead();
        newLead.LastName = 'Lee';
        newLead.FirstName = 'James';
       newLead.Company = 'TestTrigger';
       newLead.Program__c = 'Assessment & Standards Development Services';
       newLead.Proposal_Reviewer_list__c = 'Aida Walqui';
       newLead.Create_Apttus_Proposal__c = True;

        insert newLead;
       
     test.startTest();
      Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator());
      

        Database.LeadConvert lc = new Database.LeadConvert();
       lc.setLeadId(newLead.id);

        
        

       LeadStatus convertStatus = [Select Id, MasterLabel from LeadStatus where IsConverted=true limit 1];
//lc.setConvertedStatus(convertStatus.MasterLabel);
lc.setConvertedStatus('Qualified');


       Database.LeadConvertResult lcr = Database.convertLead(lc);
        
        System.assert(lcr.isSuccess());

      test.stopTest();
    }

}


 
I've created an email template that will be sent to Accounts payable once an Invoice (custom object) has been approved.  In the email, I would like to show the full approval history for that invoice. including when it was submitted, and any rejections and subsequent approval.

My problem is, I can not seem to pull the dates/times in any order that makes since.    See code - notice that the Dates and Status areUser-added image out of order.
<messaging:emailTemplate subject="A new IS Invoice has been approved." recipientType="User" relatedToType="Bill_Item__c">
 <messaging:htmlEmailBody >

    <html>
    <head>
  
    <script>
         var people, asc1 = 1,
            asc2 = 1,
            asc3 = 1;
        window.onload = function () {
            people = document.getElementById("people");
           var peps = people;
peps.reverse();
        }

        function sortTable(){
    var tbl = document.getElementById("caltbl").tBodies[0];
    var store = [];
    for(var i=0, len=tbl.rows.length; i<len; i++){
        var row = tbl.rows[i];
        var sortnr = parseFloat(row.cells[0].textContent || row.cells[0].innerText);
        if(!isNaN(sortnr)) store.push([sortnr, row]);
    }
    store.sort(function(x,y){
        return x[0] - y[0];
    });
    for(var i=0, len=store.length; i<len; i++){
        tbl.appendChild(store[i][1]);
    }
    store = null;
}
        
        </script>

</head>
      <body onload="sortTable()">
        

        <STYLE type="text/css">
        
        
   
        #DIV_Top{font-size: 24px; font-weight: Bold;  padding: 0 0 0 10px; margin: 0; background-color: #add0c8; color: #ffffff;}
#Top_Text {font-size: 18px; font-face: arial; color:#ea896a}
#Top_Text0 {font-size: 18px; font-face: arial; color:#000000}
#Print{border: solid #CCCCCC; border-width: 1;background-color: #add0c8; width: 100px; }
#Print a:link { color: #ffffff;font-size: 14px; font-weight: bold;}
#Print a:visited { color: #ffffff;font-size: 14px;font-weight: bold; }
#Print a:hover { color: #ffffff; font-size: 14px;font-weight: bold;}
#Print a:active { color: #ffffff; font-size: 14px;font-weight: bold;}


.myButton {
    -moz-box-shadow:inset 0px 1px 3px 0px #91b8b3;
    -webkit-box-shadow:inset 0px 1px 3px 0px #91b8b3;
    box-shadow:inset 0px 1px 3px 0px #91b8b3;
    background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #768d87), color-stop(1, #6c7c7c));
    background:-moz-linear-gradient(top, #768d87 5%, #6c7c7c 100%);
    background:-webkit-linear-gradient(top, #768d87 5%, #6c7c7c 100%);
    background:-o-linear-gradient(top, #768d87 5%, #6c7c7c 100%);
    background:-ms-linear-gradient(top, #768d87 5%, #6c7c7c 100%);
    background:linear-gradient(to bottom, #768d87 5%, #6c7c7c 100%);
    filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#768d87', endColorstr='#6c7c7c',GradientType=0);
    background-color:#768d87;
    -moz-border-radius:5px;
    -webkit-border-radius:5px;
    border-radius:5px;
    border:1px solid #566963;
    display:inline-block;
    cursor:pointer;
    color:#ffffff !important;
    font-family:Arial;
    font-size:15px;
    font-weight:bold;
    padding:11px 23px;
    text-decoration:none;
    text-shadow:0px -1px 0px #2b665e;
   
}
.myButton:hover {
    background:-webkit-gradient(linear, left top, left bottom, color-stop(0.05, #6c7c7c), color-stop(1, #768d87));
    background:-moz-linear-gradient(top, #6c7c7c 5%, #768d87 100%);
    background:-webkit-linear-gradient(top, #6c7c7c 5%, #768d87 100%);
    background:-o-linear-gradient(top, #6c7c7c 5%, #768d87 100%);
    background:-ms-linear-gradient(top, #6c7c7c 5%, #768d87 100%);
    background:linear-gradient(to bottom, #6c7c7c 5%, #768d87 100%);
    filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#6c7c7c', endColorstr='#768d87',GradientType=0);
    background-color:#6c7c7c;
     color:#ffffff !important;
}
.myButton:active {
    position:relative;
    top:1px;
      color:#ffffff !important;
}
.myButton:a {
    position:relative;
    top:1px;
 color:#ffffff !important;
}
.myButton:visited {
    position:relative;
    top:1px;
      color:#ffffff !important;
}
           TH.blue{font-size: 14px; font-face: arial;color: #ffffff; background: #34b0cd; 
               border-width: 2;  text-align: left} 
          TH.green {font-size: 14px; font-face: arial;color: #ffffff; background: #add0c8; 
               border-width: 2;  text-align: left} 
           TH.orange {font-size: 14px; font-face: arial;color: #ffffff; background: #ea896a; 
               border-width: 2;  text-align: left} 
               
          TD  {font-size: 14px; font-face: verdana;border: solid #Cdcdcd; border-width: 1;  } 
          TABLE {border: solid #CCCCCC; border-width: 0; }
          
TR.blue:nth-child(even) {color: #12547d}

TR.green  {color: #529384}
TR.orange  {color: #ea896a}
          TR {border: solid #CCCCCC; border-width: 1; padding: 0px;}
          
        </STYLE>
        <apex:variable var="count" value="{!0}" /> 
            
<apex:repeat var="cc" value="{!relatedTo.Bill_Payments__r}">

     <apex:outputPanel layout="none" rendered="{!cc.Allotment_User_Id__c != '-Select-'}">
   <apex:variable var="count" value="{!count+1}"/>
     </apex:outputPanel>
</apex:repeat>
        <font face="arial" size="3" color="#534e4e">
           <div id="Logo">
           </div>
           <div id="DIV_Top">
            <p>&#10004; &nbsp; Invoice Approved</p>
           </div>
           <div id="Top_Text0">
           <apex:outputText value="{!IF(count=0  ,"","**New Process**")}"/>
           </div>
            <p />
            
 
  
   
    
   
            
            The invoice related to {!relatedTo.Vendor_Account__r.Request_Type__c} <a href="  {!relatedTo.Vendor_Account__r.PO_Link__c}">{!relatedTo.Vendor_Account__r.Purchase_Order__c}</a> has been approved. <br />
            Please print this page and the associated Invoice for your records. <a href="{!relatedTo.Box_Share_Link__c}" class="myButton">Print Invoice</a>
           <p />
              <div id="Top_Text">
        Approval History
        </div>
          
<table border="0" cellspacing="0" cellpadding="5">
    <tr border-bottom="1"> 
               <th class="green">Approver</th>
               <th class="green">Date Approved</th>
               <th class="green">Status</th>
               <th class="green">Comments</th>
               </tr>
    <apex:repeat var="cx" value="{!relatedTo.ProcessSteps}">
        <tr class="green" >
           
             <td >{!cx.Actor.name}</td>
              <td><apex:outputText value="{0,date,MM'/'dd'/'yyyy}">
    <apex:param value="{!cx.ProcessInstance.CompletedDate}" /> 
</apex:outputText></td>
             
            <td>{!cx.StepStatus}</td>
           
            
           
         
            
          <td>{!cx.Comments}</td>
        </tr>
         
    </apex:repeat>                 
</table>
     <p />


     <p />
        <hr class="Top_Text"/>
             <div id="Top_Text">
             Invoice Information
             </div>       
          <table border="0" cellspacing="0" cellpadding="5">
            <tr > 
               <th class="blue">Service Name</th>
               <th class="blue">Account Number:</th>
               <th class="blue">Invoice Number:</th>
               <th class="blue">Invoice Date:</th>
               <th class="blue">Billing Cyle</th>
               <th class="blue">Month Processed:</th>
              <th class="blue">Total:</th>
             
            </tr>
                <tr class="blue">
                <td>
                <strong>{!relatedTo.Vendor_Account__r.Name}</strong>
                </td>
                <td>
                {!relatedTo.Account_Number__c}
                </td>
                 <td>
                {!relatedTo.Invoice_Number__c}
                </td>
                 <td>
               <apex:outputText value="{0,date,MM'/'dd'/'yyyy}">
    <apex:param value="{!relatedTo.Invoice_Date__c}" /> 
</apex:outputText>
                </td>
                 <td>
                <apex:outputText value="{0,date,MM'/'dd'/'yyyy}">
    <apex:param value="{!relatedTo.Billing_Cycle_Start__c}" /> 
</apex:outputText>  -  <apex:outputText value="{0,date,MM'/'dd'/'yyyy}">
    <apex:param value="{!relatedTo.Billing_Cycle_End__c}" /> 
</apex:outputText>
                </td>
                 <td>
                {!relatedTo.Month_Processed__c}
                </td>
                 <td>
                <strong>${!relatedTo.Total_Allotted_Amount__c}</strong>
                </td>
              
                   </tr>       
          </table>
          <p />
      
      
 <div id="Top_Text">
        Applied Cost Codes
                </div>
<table border="0" cellspacing="0" cellpadding="5">
   <tr border-bottom="1"> 
               <th class="orange">Cost Code</th>
               <th class="orange">User Id</th>
               <th class="orange">Amount Charged</th>
                              </tr> 
                         
<apex:repeat var="cc" value="{!relatedTo.Bill_Payments__r}">
    <tr class="grey"><td>
        {!IF(cc.Bill_Cost_Code__c = "[]","",SUBSTITUTE(SUBSTITUTE(cc.Bill_Cost_Code__c,"[", ""),"]","" ))}
        
       </td>
       <td>{!IF(cc.Allotment_User_Id__c = "-Select-","",  cc.Allotment_User_Id__c )}
     
       </td>
       <td style="text-align:right">${!cc.Allotment_Amount__c}</td></tr>
</apex:repeat>
     </table>


<p />
</font>

   </body>
    </html>
  </messaging:htmlEmailBody> 
<messaging:plainTextEmailBody >

The invoice related to PO# {!relatedTo.Vendor_Account__r.Purchase_Order__c} has been approved.

Please print this page and the associated Invoice for your records located here >> {!relatedTo.Box_Share_Link__c}

Invoice Information:

Service Name: {!relatedTo.Vendor_Account__r.Name}
Account Number: {!relatedTo.Account_Number__c}
Invoice Number:   {!relatedTo.Invoice_Number__c}
Invoice Date: <apex:outputText value="{0,date,MM'/'dd'/'yyyy}"><apex:param value="{!relatedTo.Invoice_Date__c}" /> </apex:outputText>
Billing Cyle:  <apex:outputText value="{0,date,MM'/'dd'/'yyyy}"><apex:param value="{!relatedTo.Billing_Cycle_Start__c}" /></apex:outputText>  -  <apex:outputText value="{0,date,MM'/'dd'/'yyyy}"><apex:param value="{!relatedTo.Billing_Cycle_End__c}" /> </apex:outputText>
Month Processed: {!relatedTo.Month_Processed__c}
Total: {!relatedTo.Total_Allotted_Amount__c}
             
Approval History:
 <apex:repeat var="cx" value="{!relatedTo.ProcessSteps}">        
{!cx.Actor.name}
<apex:outputText value="{0,date,MM'/'dd'/'yyyy}">
<apex:param value="{!cx.ProcessInstance.CompletedDate}" /> 
</apex:outputText>         
{!cx.StepStatus}
{!cx.Comments}
</apex:repeat>          
           
//history = SELECT Id, (SELECT Actor.name, CompletedDate, StepStatus)
FROM ProcessInstance           
           
Applied Cost Codes / User ID
                        
<apex:repeat var="cc" value="{!relatedTo.Bill_Payments__r}">
{!IF(cc.Bill_Cost_Code__c = "[]","",cc.Bill_Cost_Code__c)}{!IF(cc.Allotment_User_Id__c = "-Select-","",cc.Allotment_User_Id__c)}
</apex:repeat>             

</messaging:plainTextEmailBody>
</messaging:emailTemplate>

 
So, I've managed to learn a bit of apex. Now I really need a hand with testing the code so that I can move it to production.  Could someone please help me with the following?
public class multiAddCEx {

public Id cID = ApexPages.currentPage().getParameters().get('Id'); //grab the Vendor Bill ID
//Integer count = 0;
string num_name = '';
// Lookup against Available Cost Codes Junction Object
public List<SelectOption> costcodes {get; set;}
    public multiAddCEx ()
    {
        costcodes  = new List<SelectOption>() ;
          for(Cost_Code_Connection__c cc : [select Cost_Code_Junction2__r.Cost_Code_ID__c , Cost_Code_Percentage__c, id,name from Cost_Code_Connection__c where Cost_Code_Connection__c.Bill_Item_Junction__c =: cID order by Cost_Code_Junction2__r.Cost_Code_ID__c, Cost_Code_Percentage__c ])
        {
        costcodes.add(new SelectOption(cc.Cost_Code_Junction2__r.Cost_Code_ID__c +' - '+ cc.Cost_Code_Percentage__c +'%',cc.Cost_Code_Junction2__r.Cost_Code_ID__c +' - '+ cc.Cost_Code_Percentage__c +'%' )) ;
        }
  }
//Lookup to find User Intranet ID in User records
public List<SelectOption> intranetids {get; set;}
    {
        intranetids = new List<SelectOption>() ;
        intranetids.add(new SelectOption('-Select-','-Select-'));
        for(User ui : [select Intranet_ID__c , id, name, IsActive from User where IsActive = True order by Intranet_ID__c])
                {
if (ui.Intranet_ID__c != null){ 
num_name = ui.name;
        intranetids.add(new SelectOption(ui.Intranet_ID__c, ui.Intranet_ID__c +' - '+ num_name  )) ;
}
        }    
    }
List <Bill_Allotment__c> CExList;
public Id getID {get; set;}
public PageReference reset()  { //pull at most 8 expense records to show so we don't clutter up the page
CExList = [select name, Bill_Allotment__c.Phone_Number__c ,  Allotment_Amount__c, Bill_Allotment__c.Allotment_User_Id__c,  Bill_Allotment__c.Bill_Cost_Code__c  from Bill_Allotment__c where Bill_Item__c =: cID order by createddate limit 0 ];
return null; }
public List <Bill_Allotment__c> getCExs() {
 if(CExList == null) reset();
 return CExList;
  }
public void setAccounts(List <Bill_Allotment__c> cexs) {
   CExList = cexs;}
public PageReference save() {//upsert records on save
try{
       upsert CExList;
       ApexPages.Message myMsg = new ApexPages.message(ApexPages.Severity.Info, 'Records Saved Successfully'); //show confirmation message on save
ApexPages.addMessage(myMsg);
return null;   
       }
    catch(DmlException ex){
   
        ApexPages.addMessages(ex);
       }
    return null;       
}
//ApexPages.Message myMsg = new ApexPages.message(ApexPages.Severity.Info, 'Records Saved Successfully'); //show confirmation message on save
//ApexPages.addMessage(myMsg);
//return null;}
public PageReference cancel() {//close window without upsert
return null;
}
public PageReference add() {
//count++;
CExList.add(New Bill_Allotment__c(Bill_Item__c = cID)); //add records to Bill Items and associate with current Bill
return null; }
 //public Integer getCount() {
        //return count;
   // }
}