This takes in an array of data built from a source workbook, builds a set of "flags" based on the data in each row of the array. Then it creates a new finalRng
array that will, based on a set of logic from the business, create new rows based on the data.
I think there are a ton of ways to accomplish what I am looking for but this code is what I have come up with so far (code is in a UserForm module):
Option Explicit
Dim nonLoanCodes As Variant
Dim sourceColumns As Variant
Dim finalRng()
Dim trimmedRange As Variant
Dim log As New Logger
Dim beforeTaxPercentSum As Double
Dim beforeTaxFlatSum As Long
Dim rothPercentSum As Double
Dim rothFlatSum As Long
Dim logMessage As String
Dim strFirstFile, strSecondFile, strThirdFile As String
Dim wbkFirstFile, wbkSecondFile, wbkThirdFile, wbkConfigFile As Workbook
Private Sub btnBuildImportFile_Click()
'
' This function will build a 401k/Loan Worksheet for upload into UltiPro
'
On Error GoTo ErrorHappened
Dim lastRow As Long
Dim allRowFlags() As FlagBag
Dim payrollDate As String
Dim cell As Range
Application.DisplayAlerts = False
payrollDate = cmbPayrollDate.Value
'Declare source and destination workbooks
strFirstFile = lblFileName.Caption
strSecondFile = ThisWorkbook.path & "\template.xlsx"
strThirdFile = ThisWorkbook.path & "\ultiImport_" + Format(Now, _
"yyyy_mm_dd-hh_mm") + ".xlsx"
Set wbkFirstFile = Workbooks.Open(strFirstFile)
Set wbkSecondFile = Workbooks.Open(strSecondFile)
'Function call to validate whether the chosen source file is formatted correctly
If IsValidImportSheet(wbkFirstFile) = False Then
lblFileName.Caption = ""
Label2.Caption = ""
wbkFirstFile.Close
Else
'Function call to get last row from source sheet and build the source range and destination columns
lastRow = GetLastRowOnSheet(wbkFirstFile)
'Grab only the necessary values from the source worksheet and put them into an array
With wbkFirstFile.Sheets(1).Range("H2:W" & lastRow)
trimmedRange = Application.Index(.Value2, .Worksheet.Evaluate("ROW(" & _
.Columns(1).Address & ")-1"), Array(1, 9, 10, 14, 15, 16))
End With
'loop input file temp range and set flags/properties for each record
CalculateRowValues allRowFlags()
Worksheets.Add
ActiveSheet.Name = "Temp"
ActiveSheet.Move After:=Sheets(ActiveWorkbook.Sheets.count)
Range("A1:G" & UBound(finalRng)) = finalRng
'Write all to output template
ActiveSheet.Range("A1:A" & UBound(finalRng)).Copy _
Destination:=wbkSecondFile.Sheets(1).Range("B3:B" & UBound(finalRng))
ActiveSheet.Range("F1:F" & UBound(finalRng)).Copy _
Destination:=wbkSecondFile.Sheets(1).Range("C3:C" & UBound(finalRng))
ActiveSheet.Range("B1:B" & UBound(finalRng)).Copy _
Destination:=wbkSecondFile.Sheets(1).Range("F3:F" & UBound(finalRng))
ActiveSheet.Range("C1:C" & UBound(finalRng)).Copy _
Destination:=wbkSecondFile.Sheets(1).Range("G3:G" & UBound(finalRng))
'Apply payroll date to column N
For Each cell In wbkSecondFile.Sheets(1).Range("N3:N" & _
UBound(finalRng) + 2)
cell.Value = cmbPayrollDate.Value
Next cell
wbkFirstFile.Close
wbkSecondFile.Sheets("Temp").Delete
'Save template as a new file
SaveActiveSheet wbkSecondFile, strThirdFile
wbkSecondFile.Close
'Log totals to external file
logMessage = ("New Entry: " & Chr(13) & Chr(13) & "Source File Name: " & _
strThirdFile & Chr(13) & Chr(13) & "Total Rows On Source Sheet: " & _
UBound(trimmedRange) & Chr(13) & Chr(13) & "Before Tax Deduction Percent Sum: " & _
beforeTaxPercentSum & Chr(13) & Chr(13) & "Before Tax Deduction Flat Sum: " _
& beforeTaxFlatSum & Chr(13) & Chr(13) & "Roth Percent Sum: " & _
rothPercentSum & Chr(13) & Chr(13) & "Roth Flat Amount Sum: " & rothFlatSum _
& Chr(13))
log.logEntry (logMessage)
PostBuildResultsAndCleanup strThirdFile
Application.DisplayAlerts = True
End If
ExitNow:
On Error Resume Next
Exit Sub
ErrorHappened:
MsgBox Err.Description, vbCritical, "Main:btnBuildImportFile_Click"
Resume ExitNow
Resume
End Sub
Function IsValidImportSheet(ByVal book As Workbook) As Boolean
Dim c, rLastCell As Range
Dim columnLetter, importRange As String
Dim counter As Integer: counter = 1
Set rLastCell = book.Sheets(1).Cells.Find(What:="*", After:=book.Sheets(1).Cells(1, 1), LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False)
columnLetter = Col_Letter(CInt(rLastCell.Column))
importRange = "A1:" & columnLetter & "1"
For Each c In book.Worksheets(1).Range(importRange).Cells
If sourceColumns(counter, 1) <> c.Value Then
IsValidImportSheet = False
MsgBox "Column: " & Chr(34) & c.Value & Chr(34) & " not expected. Import cancelled."
Exit Function
End If
counter = counter + 1
Next
IsValidImportSheet = True
End Function
Function Col_Letter(lngCol As Long) As String
Dim vArr
vArr = Split(Cells(1, lngCol).Address(True, False), "$")
Col_Letter = vArr(0)
End Function
Function CalculateRowValues(ByRef allRowFlags() As FlagBag)
On Error GoTo ErrorHappened
Dim i, cnt As Long
ReDim allRowFlags(UBound(trimmedRange) - 1)
For i = 1 To UBound(trimmedRange, 1)
Dim rowFlag As FlagBag
'Case statements will not work here as we have multiple scenarios that need to be checked
'Handles all rows where there is only one deduction type
If trimmedRange(i, 2) > 0 Then
trimmedRange(i, 2) = trimmedRange(i, 2) * 0.01
End If
If trimmedRange(i, 4) > 0 Then
trimmedRange(i, 4) = trimmedRange(i, 4) * 0.01
End If
If trimmedRange(i, 6) = "Y" Then
With rowFlag
.fiftyPlus = True
.rowNumber = i + 1
End With
End If
If trimmedRange(i, 2) >= 0 And IsEmpty(trimmedRange(i, 2)) = False Then
'Sets 401CP
If rowFlag.fiftyPlus = True Then
ReDim Preserve finalRng(5, cnt)
finalRng(0, cnt) = trimmedRange(i, 1)
finalRng(1, cnt) = trimmedRange(i, 2)
finalRng(5, cnt) = nonLoanCodes(3, 1)
beforeTaxPercentSum = beforeTaxPercentSum + trimmedRange(i, 2)
cnt = cnt + 1
'Sets 401P
Else
ReDim Preserve finalRng(5, cnt)
finalRng(0, cnt) = trimmedRange(i, 1)
finalRng(1, cnt) = trimmedRange(i, 2)
finalRng(5, cnt) = nonLoanCodes(1, 1)
beforeTaxPercentSum = beforeTaxPercentSum + trimmedRange(i, 2)
cnt = cnt + 1
End If
End If
If trimmedRange(i, 3) >= 0 And IsEmpty(trimmedRange(i, 3)) = False Then
'Sets 401CF
If rowFlag.fiftyPlus = True Then
ReDim Preserve finalRng(5, cnt)
finalRng(0, cnt) = trimmedRange(i, 1)
finalRng(2, cnt) = trimmedRange(i, 3)
finalRng(5, cnt) = nonLoanCodes(4, 1)
beforeTaxFlatSum = beforeTaxFlatSum + trimmedRange(i, 3)
cnt = cnt + 1
'Sets 401F
Else
ReDim Preserve finalRng(5, cnt)
finalRng(0, cnt) = trimmedRange(i, 1)
finalRng(2, cnt) = trimmedRange(i, 3)
finalRng(5, cnt) = nonLoanCodes(2, 1)
beforeTaxFlatSum = beforeTaxFlatSum + trimmedRange(i, 3)
cnt = cnt + 1
End If
End If
If trimmedRange(i, 4) >= 0 And IsEmpty(trimmedRange(i, 4)) = False Then
'Sets ROTHC
If rowFlag.fiftyPlus = True Then
ReDim Preserve finalRng(5, cnt)
finalRng(0, cnt) = trimmedRange(i, 1)
finalRng(1, cnt) = trimmedRange(i, 4)
finalRng(5, cnt) = nonLoanCodes(7, 1)
rothPercentSum = rothPercentSum + trimmedRange(i, 4)
cnt = cnt + 1
'Sets ROTH
Else
ReDim Preserve finalRng(5, cnt)
finalRng(0, cnt) = trimmedRange(i, 1)
finalRng(1, cnt) = trimmedRange(i, 4)
finalRng(5, cnt) = nonLoanCodes(5, 1)
rothPercentSum = rothPercentSum + trimmedRange(i, 4)
cnt = cnt + 1
End If
End If
If trimmedRange(i, 5) >= 0 And IsEmpty(trimmedRange(i, 5)) = False Then
'Sets ROTHFC
If rowFlag.fiftyPlus = True Then
ReDim Preserve finalRng(5, cnt)
finalRng(0, cnt) = trimmedRange(i, 1)
finalRng(2, cnt) = trimmedRange(i, 5)
finalRng(5, cnt) = nonLoanCodes(8, 1)
rothFlatSum = rothFlatSum + trimmedRange(i, 5)
cnt = cnt + 1
'Sets ROTHF
Else
ReDim Preserve finalRng(5, cnt)
finalRng(0, cnt) = trimmedRange(i, 1)
finalRng(2, cnt) = trimmedRange(i, 5)
finalRng(5, cnt) = nonLoanCodes(6, 1)
rothFlatSum = rothFlatSum + trimmedRange(i, 5)
cnt = cnt + 1
End If
End If
allRowFlags(i - 1) = rowFlag
rowFlag.deductionCode = ""
rowFlag.fiftyPlus = False
rowFlag.rowNumber = 0
Next i
finalRng = Application.Transpose(finalRng)
ExitNow:
On Error Resume Next
Exit Function
ErrorHappened:
MsgBox Err.Description, vbCritical, "Main:CalculateRowValues"
Resume ExitNow
Resume
End Function
Function GetLastRowOnSheet(ByVal book As Workbook) As Long
'
'This function will get the last used row on the source spreadsheets
'
On Error GoTo ErrorHappened
Dim TempRange As Range
Set TempRange = book.Sheets(1).Cells.SpecialCells(xlCellTypeLastCell)
GetLastRowOnSheet = TempRange.Row
ExitNow:
On Error Resume Next
Exit Function
ErrorHappened:
MsgBox Err.Description, vbCritical, "Main:GetLastRowOnSheet"
Resume ExitNow
Resume
End Function
Sub SaveActiveSheet(ByVal book As Workbook, ByVal fileName As String)
'
'Saves the active sheet to a new workbook excluding the code tabs
'
On Error GoTo ErrorHappened
Dim ws As Worksheet
For Each ws In book.Worksheets 'SetVersions
If ws.Name = "Upload Template" Then
Dim wb As Workbook
Set wb = ws.Application.Workbooks.Add
ws.Copy Before:=wb.Sheets(1)
wb.SaveAs fileName
Set wb = Nothing
End If
Next ws
ExitNow:
On Error Resume Next
Exit Sub
ErrorHappened:
MsgBox Err.Description, vbCritical, "Main:SaveActiveSheet"
Resume ExitNow
Resume
End Sub
Sub CleanNewBook()
'
'Cleans the new workbook by removing superfluous tabs
'
On Error GoTo ErrorHappened
Dim ws As Worksheet
For Each ws In wbkThirdFile.Worksheets
If ws.Name <> "Upload Template" Then
ws.Delete
End If
Next ws
wbkThirdFile.Sheets(1).Name = "Sheet1"
wbkThirdFile.Save
ExitNow:
On Error Resume Next
Exit Sub
ErrorHappened:
MsgBox Err.Description, vbCritical, "Main:CleanNewBook"
Resume ExitNow
Resume
End Sub
Sub PostBuildResultsAndCleanup(ByVal resultFileName As String)
'Cleans up form and files as well as displays build results
On Error GoTo ErrorHappened
Set wbkThirdFile = Workbooks.Open(resultFileName)
BtnBuildImportFile.Enabled = False
CleanNewBook
wbkThirdFile.Close
lblFileName.Caption = ""
Label2.Visible = False
txtDetails.Text = Replace(logMessage, "New Entry: " & Chr(13), "")
Label3.Visible = True
lblResultFile.Caption = resultFileName
lblResultFile.MousePointer = fmMousePointerUpArrow
MsgBox "File Saved: " & resultFileName
ExitNow:
On Error Resume Next
Exit Sub
ErrorHappened:
MsgBox Err.Description, vbCritical, "Main:PostBuildResultsAndCleanup"
Resume ExitNow
Resume
End Sub
Private Sub BtnChooseSourceFile_Click()
'
' Display Windows OpenFileDialog for choosing the input file
'
On Error GoTo ErrorHappened
Dim oFilePicker As New FilePicker
oFilePicker.SetupFilePicker
ExitNow:
On Error Resume Next
Exit Sub
ErrorHappened:
MsgBox Err.Description, vbCritical, "Main:btnChooseSourceFile_Click"
Resume ExitNow
Resume
End Sub
Private Sub LblResultFile_Click()
'
'Sets up hyperlink for resulting file
'
On Error GoTo ErrorHappened
Dim pth As String
If lblResultFile.Caption <> "" Then
pth = GetDirectory(lblResultFile.Caption)
'link = pth
Unload Main
ActiveWorkbook.FollowHyperlink Address:=pth, NewWindow:=True
Else
MsgBox "Sorry, No Link Available"
End If
ExitNow:
On Error Resume Next
Exit Sub
ErrorHappened:
MsgBox Err.Description, vbCritical, "Main:lblResultFile_Click"
Resume ExitNow
Resume
End Sub
Function GetDirectory(fileName)
'
'Strips filename from the path to support the hyperlink for the result file
'
On Error GoTo ErrorHappened
GetDirectory = Left(fileName, InStrRev(fileName, "\"))
ExitNow:
On Error Resume Next
Exit Function
ErrorHappened:
MsgBox Err.Description, vbCritical, "Main:GetDirectory"
Resume ExitNow
Resume
End Function
Private Sub UserForm_Click()
End Sub
Private Sub UserForm_Initialize()
Dim payrollDateListItems As Variant
Dim strConfigFile As String
strConfigFile = ThisWorkbook.path & "\configuration.xlsx"
Set wbkConfigFile = Workbooks.Open(strConfigFile)
nonLoanCodes = wbkConfigFile.Sheets(1).Range("A2:A9")
payrollDateListItems = wbkConfigFile.Sheets(3).Range("A2:A27")
sourceColumns = wbkConfigFile.Sheets(4).Range("A2:A44")
Main.cmbPayrollDate.List = payrollDateListItems
wbkConfigFile.Close
End Sub