Pages

Wednesday, September 30, 2009

The Contract Calendar (aka "Effectivity Calendar")

My company has a report template I created that generates an executable agreement document based on Contract records in CRM. It does a lot of pretty formatting, but one thing I never had with it is a proper rendering of the contract's calendar (you know, that button on top of the contract).

This is mostly because the data for that calendar is saved in a single column called "effectivitycalendar" as a 168-character string of minus and plus signs. Not very helpful, by itself.

So, I initially took a shortcut, and output dates/times to the report based on the contract's service level. This worked fine, until recently I received a request to add another range of effective times to the contract (and by extension, the report). Without going into too much detail, it would have been ugly to rewrite portions of my contract customizations and report template. So, I banged out the following VBA code and placed it into the report:

Function ConvertEffectivityCalendar(ByVal effectivityString As String) As String 
  Dim dailyCodeArray() As String = New String() {Mid(effectivityString, 1, 24), Mid(effectivityString, 25, 24), Mid(effectivityString, 49, 24), Mid(effectivityString, 73, 24), Mid(effectivityString, 97, 24), Mid(effectivityString, 121, 24), Mid(effectivityString, 145, 24)}
  Dim dailyCode As String 
  Dim currentDay As Integer 
  Dim results As String 
  Dim startTime As Integer 
  Dim endTime As Integer 
  Dim nextStartTime As Integer 
  Dim nextEndTime As Integer 
  Dim lastStartTime As Integer 
  Dim lastEndTime As Integer 
  Dim today As String 
  
  For currentDay = 0 To 6 
    dailyCode = dailyCodeArray(currentDay)
    startTime = InStr(dailyCode, "+")
    endTime = InStrRev(dailyCode, "+")
    nextStartTime = 0 
    nextEndTime = 0 
    lastStartTime = 0 
    lastEndTime = 0 
    
    If currentDay < 6 Then 
      nextStartTime = InStr(dailyCodeArray(currentDay + 1), "+")
      nextEndTime = InStrRev(dailyCodeArray(currentDay + 1), "+")
    End If 
    
    If currentDay > 0 Then 
      lastStartTime = InStr(dailyCodeArray(currentDay - 1), "+")
      lastEndTime = InStrRev(dailyCodeArray(currentDay - 1), "+")
    End If 
    
    Select Case currentDay 
      Case 0 
        today = "Sunday" 
      Case 1 
        today = "Monday"
      Case 2 
        today = "Tuesday" 
      Case 3
        today = "Wednesday"
      Case 4 
        today = "Thursday" 
      Case 5 
        today = "Friday" 
      Case 6 today = "Saturday" 
    End Select
    
    If startTime <> 0 And endTime <> 0 Then 
      If startTime <> lastStartTime Or endTime <> lastEndTime Then 
        If Len(results) > 1 Then 
          results = results + Chr(10) 
        End If 
        
        results = results + today 
      Else If startTime <> nextStartTime Or endTime <> nextEndTime Then
        results = results + " - " + today
      End If 
      
      If startTime <> nextStartTime Or endTime <> nextEndTime Then 
        results = results + Chr(10) 
        startTime = startTime - 1 
        
        If startTime <> 0 And endTime <> 23 Then 
          If startTime > 12 Then 
            results = results + CStr(startTime - 12) + ":00 pm" 
          Else If startTime = 0 Then 
            results = results + "12:00 am" 
          Else 
            results = results + CStr(startTime) + ":00 am" 
          End If 
        
          results = results + " to "
          endTime = endTime - 1 
          
          If endTime > 12 Then 
            results = results + CStr(endTime - 12) + ":00 pm"
          Else If endTime = 0 Then 
            results = results + "12:00 am" 
          Else 
            results = results + CStr(endTime) + ":00 am" 
          End If 
        Else 
          results = results + "All Day"
        End If 
      End If 
    End If 
  Next 
  
  Return results 
End Function

What it returns is a string, specially formatted for the particulars of my report. The nice thing about it, is that it summarizes the data. If the times blocked out on the calendar are identical for consecutive days, it prints the range of dates in the format "[Start Date] - [End Date]" and places the effective times underneath it in the format "[Start Time] to [End Time]". If there is variance in the effective times on following dates, it prints the unique start and end times for each date.

This may not be the most efficient, or portable method of converting the "effectivitycalendar" data into readable form, but it works nicely for my implementation and allows for a great deal more flexibility than I had. It should be noted that this code assumes all time points between the start and the end for any given day are filled in. This code would need heavy modification to accommodate several time-ranges for a single day.