Overview
This is a major update to my original Transaction Splitter for Excel (VBA) where I rewrote most of the code to make it more efficient and added the saved capabilities.
Same caveats as the original one.
Installation
I would recommend installing this only if you have some familiarity with VBA. The code works, but it’s VBA, so you should be able to know how to install and how to run. The code is here:
VBA Code
`Sub SplitTransactionWithCustomAmounts()
Dim ws As Worksheet
Dim selectedRow As Range
Dim headerRow As Range
Dim descCol As Long
Dim amtCol As Long
Dim catCol As Long
Dim noteCol As Long
Dim dateCol As Long
Dim numRowsToAdd As Long
Dim i As Long
Dim splitAmts() As Variant
Dim splitCat() As String
Dim splitDesc() As String
Dim totalSplitAmt As Double
' Set references to the active worksheet, selected row, and header row
Set ws = ActiveSheet
Set selectedRow = ws.Cells.Find(What:="*", SearchDirection:=xlPrevious)
Set headerRow = selectedRow.End(xlUp)
amtCol = 4
dateCol = 1
descCol = 2
catCol = 3
noteCol = 21
' Get the original transaction information from the selected row
Dim origDesc As String
Dim origAmt As Double
Dim origDate As String
origDesc = Cells(ActiveCell.Row, descCol)
origAmt = Cells(ActiveCell.Row, amtCol)
origDate = Cells(ActiveCell.Row, dateCol)
origrow = ActiveCell.Row
' Prompt user to confirm split and verify $0 split
Dim confirmMsg As String
If origAmt = 0 Then
confirmMsg = “Amount of transaction on selected row is $0. Do you still want to continue?”
If MsgBox(confirmMsg, vbYesNo, “Continue?”) <> vbYes Then
Exit Sub
End If
End If
confirmMsg = “Please confirm the following transaction details:” & vbCrLf _
& "Date: " & origDate & vbCrLf _
& "Description: " & origDesc & vbCrLf _
& "Amount: " & origAmt & vbCrLf & vbCrLf _
& “Do you want to split this transaction?”
If MsgBox(confirmMsg, vbYesNo, “Confirm Split”) <> vbYes Then
Exit Sub
End If
Dim fullinput As String
Dim splitinput As Variant
Dim useSavedSplit As VbMsgBoxResult
useSavedSplit = MsgBox(“Do you want to use a saved split?”, vbYesNo + vbQuestion, “Use Saved Split”)
If useSavedSplit = vbYes Then
Dim uniqueSplitValues As Variant
uniqueSplitValues = GetUniqueValues()
' User wants to use a saved split
Dim splitName As String
splitName = InputBox("Enter the name of the saved split:" & vbNewLine & Join(uniqueSplitValues, vbNewLine), "Saved Split Names")
If splitName = "" Then Exit Sub ' Exit the sub if the user cancels the input box
Dim splitInfoSheet As Worksheet
Dim splitInfoRow As Range
Set splitInfoSheet = ThisWorkbook.Sheets("SavedSplits")
Dim firstSplitRow As Range
Set firstSplitRow = splitInfoSheet.Columns(“A”).Find(What:=splitName, LookIn:=xlValues, LookAt:=xlWhole)
If Not firstSplitRow Is Nothing Then
Dim lastSplitRow As Range
Set lastSplitRow = firstSplitRow
Do While lastSplitRow.Cells(1, 1) = splitName
Set lastSplitRow = lastSplitRow.Offset(1, 0)
Loop
Set lastSplitRow = lastSplitRow.Offset(-1, 0)
numRowsToAdd = lastSplitRow.Row - firstSplitRow.Row + 1
ReDim splitAmts(1 To numRowsToAdd)
ReDim splitCat(1 To numRowsToAdd)
ReDim splitDesc(1 To numRowsToAdd)
For i = 1 To numRowsToAdd
splitAmts(i) = firstSplitRow.Cells(i, 3)
splitCat(i) = firstSplitRow.Cells(i, 2)
splitDesc(i) = firstSplitRow.Cells(i, 4)
Next i
For i = 1 To numRowsToAdd
fullinput = Application.InputBox(“Enter the amount, category, and description for split " _
& vbNewLine & i & " of " & numRowsToAdd & " (each separated by a comma):” & vbNewLine & _
vbNewLine & "Current values: Amount: " & Format(splitAmts(i), “$#,##0.00”) & ", Category: " & _
splitCat(i) & ", Description: " & splitDesc(i) & vbNewLine & _
“You may leave a field blank to keep its current value.”)
If fullinput <> "" Then
' User entered new values, update the corresponding elements in the split arrays
splitinput = Split(fullinput, ",")
If UBound(splitinput) >= 0 And IsNumeric(splitinput(0)) Then _
splitAmts(i) = CDbl(splitinput(0))
If UBound(splitinput) >= 1 Then _
splitCat(i) = Trim(splitinput(1))
If UBound(splitinput) >= 2 Then _
splitDesc(i) = Trim(splitinput(2))
End If
' Last chance to exit.
totalSplitAmt = totalSplitAmt + splitAmts(i)
Next i
If Round(totalSplitAmt, 4) <> Round(origAmt, 4) Then
MsgBox “The total amount of the splits does not equal the original amount. Please adjust the split amounts.”, vbExclamation
Exit Sub
End If
confirmMsg = “Please confirm the following splits:” & vbNewLine & vbNewLine
For i = 1 To numRowsToAdd
confirmMsg = confirmMsg & " Split " & i & “: Amount:” & Format(splitAmts(i), “$#,##0.00”) & _
" Category: " & splitCat(i) & " Desc: " & splitDesc(i) & vbNewLine
Next i
confirmMsg = confirmMsg & vbNewLine & "Total: " & Format(totalSplitAmt, “$#,##0.00”) & vbNewLine & vbNewLine & “Is this correct?”
’ Ask user to confirm the splits
Dim confirmResult As VbMsgBoxResult
’ confirmResult = MsgBox(confirmMsg, vbYesNo + vbQuestion, “Confirm Splits”)
confirmResult = MsgBox(confirmMsg, vbYesNo + vbQuestion + vbDefaultButton2, “Confirm Splits”)
If confirmResult = vbYes Then
InsertRowsForSplits numRowsToAdd, amtCol, catCol, descCol, noteCol, splitAmts, splitCat, splitDesc
' Show success message to user
MsgBox "The transaction has been split successfully.", vbInformation, "Split Transaction"
Exit Sub
Else
’ Show message to user that the split was cancelled
MsgBox “The split transaction was cancelled.”, vbExclamation, “Split Transaction”
Exit Sub
End If
Else
' Split information not found, display an error message and exit the sub
MsgBox "Saved split not found. Please check the name and try again.", vbExclamation, "Split Not Found"
Exit Sub
End If
Else
’ User wants to enter the split information manually
numRowsToAdd = Application.InputBox("Enter the number of splits needed: (include the original row in the split) ", “Number of Splits”)
End If
If numRowsToAdd < 2 Then Exit Sub ’ Exit the sub if the user inputs 0 or a negative number
ReDim splitAmts(1 To numRowsToAdd)
ReDim splitCat(1 To numRowsToAdd)
ReDim splitDesc(1 To numRowsToAdd)
For i = 1 To numRowsToAdd
fullinput = Application.InputBox(“Enter the amount, category, and description for split " _
& vbNewLine & i & " of " & numRowsToAdd & " (each separated by a comma):” & vbNewLine & _
vbNewLine & “You may leave a field blank, but you must still put in a comma.” _
& vbNewLine & “Total split so far: $” & totalSplitAmt & “. Original Amount: $” & origAmt & " Amount Left to Split: $" & origAmt - totalSplitAmt)
splitinput = Split(fullinput, ",")
splitAmts(i) = splitinput(0)
splitCat(i) = splitinput(1)
splitDesc(i) = splitinput(2)
If Not IsNumeric(splitAmts(i)) Or splitAmts(i) = 0 Then
MsgBox "Invalid input for split amount. Please enter a valid number.", vbExclamation
Exit Sub
End If
totalSplitAmt = totalSplitAmt + splitAmts(i)
Next i
If Round(totalSplitAmt, 4) <> Round(origAmt, 4) Then
MsgBox "The total amount of the splits does not equal the original amount. Please adjust the split amounts.", vbExclamation
Exit Sub
End If
’ Last chance to exit.
confirmMsg = “Please confirm the following splits:” & vbNewLine & vbNewLine
For i = 1 To numRowsToAdd
confirmMsg = confirmMsg & " Split " & i & “: Amount:” & Format(splitAmts(i), “$#,##0.00”) & _
" Category: " & splitCat(i) & " Desc: " & splitDesc(i) & vbNewLine
Next i
confirmMsg = confirmMsg & vbNewLine & "Total: " & Format(totalSplitAmt, “$#,##0.00”) & vbNewLine & vbNewLine & “Is this correct?”
’ Ask user to confirm the splits
’ Dim confirmResult As VbMsgBoxResult
’ confirmResult = MsgBox(confirmMsg, vbYesNo + vbQuestion, “Confirm Splits”)
confirmResult = MsgBox(confirmMsg, vbYesNo + vbQuestion + vbDefaultButton2, “Confirm Splits”)
If confirmResult = vbYes Then
InsertRowsForSplits numRowsToAdd, amtCol, catCol, descCol, noteCol, splitAmts, splitCat, splitDesc
' Show success message to user
MsgBox "The transaction has been split successfully.", vbInformation, "Split Transaction"
Else
’ Show message to user that the split was cancelled
MsgBox “The split transaction was cancelled.”, vbExclamation, “Split Transaction”
Exit Sub
End If
End Sub
Function GetUniqueValues() As Variant
'Create a reference to the SavedSplit worksheet
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets(“SavedSplits”)
'Create a dictionary to store the unique values
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
'Find the last row in Column A of the SavedSplit worksheet
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
'Loop through the values in Column A of the SavedSplit worksheet and add them to the dictionary
Dim i As Long
For i = 2 To lastRow
dict(ws.Cells(i, "A").Value) = 1
Next i
'Return the unique values as an array
GetUniqueValues = dict.Keys
End Function
Private Sub InsertRowsForSplits(ByVal numRowsToAdd As Long, ByVal amtCol As Long, ByVal catCol As Long, _
ByVal descCol As Long, ByVal noteCol As Long, ByRef splitAmts() As Variant, _
ByRef splitCat() As String, ByRef splitDesc() As String)
Dim i As Long
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
' Update amount, category, and description for original row
Cells(ActiveCell.Row, amtCol).Value = splitAmts(1)
Cells(ActiveCell.Row, catCol).Value = splitCat(1)
Cells(ActiveCell.Row, descCol).Value = splitDesc(1)
Cells(ActiveCell.Row, noteCol).Value = FormatCurrency(Cells(ActiveCell.Row, amtCol).Value) & " of " & _
FormatCurrency(origAmt) & " split from " & origDesc & " on " & origDate
' Insert new rows for additional splits (skip the first row as it's already updated)
For i = 2 To numRowsToAdd
' Insert a new row
Rows(ActiveCell.Row + i - 1).Insert Shift:=xlDown
' Copy data from original row
Rows(ActiveCell.Row).Copy Rows(ActiveCell.Row + i - 1)
' Update amount for split
Cells(ActiveCell.Row + i - 1, amtCol).Value = splitAmts(i)
' Update category for split
Cells(ActiveCell.Row + i - 1, catCol).Value = splitCat(i)
' Update description for split
Cells(ActiveCell.Row + i - 1, descCol).Value = splitDesc(i)
' Update note for split
Cells(ActiveCell.Row + i - 1, noteCol).Value = FormatCurrency(splitAmts(i)) & " of " & _
FormatCurrency(origAmt) & " split from " & origDesc & " on " & origDate
Next i
' Reset the selection to the first cell in the original row
Cells(ActiveCell.Row, amtCol).Select
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
`
The code itself is made up of several subs and functions to make it easier to maintain and run.
Setup
First thing you have to do is go to the code and make sure the column numbers for the Transaction table are correct. In my code it’s:
amtCol = 4
dateCol = 1
descCol = 2
catCol = 3
noteCol = 21
Then, if you will be using the saved splits feature, you need to add a sheet called SavedSplits with the following columns in this order:
splitName,Category,Amount,Description
Usage
Usage is as before, with the addition of Saved Splits. If you run a saved split and the details are the same, you can just press enter. Otherwise, you can fill in the information for that split.
Permissions
Is it ok for others to copy, use, and modify your workflow?
Yes
Notes
I tested it, but you never know how VBA acts, so use with caution. As before, there is a final confirmation that you can always break in case things look wonky.
FAQ
Optionally, add common questions and answers…