Search code examples
excelvbaauditing

require code for audit trails using vba code


I have a sheet named mapping and it contains 3 columns namely Fundcode(b3),subsription rate(c3) and redemption rate(d3)

so values are entered from row 4 for these headers..i wanted audit trails for values entered in these cells with the user name .

I tried with some code,but it did not help me. As i am new to macro, i do not know how to resolve it

Private Sub Worksheet_Change(ByVal Target As Range)
 Dim strAddress As String
    Dim val
    Dim dtmTime As Date
    Dim Rw As Long

    If Intersect(Target, Range("B4:D4")) Is Nothing Then Exit Sub

    dtmTime = Now()
    val = Target.value
    strAddress = Target.Address

    Rw = Sheets("shtMapping").Range("B" & Rows.Count).End(xlUp).Row + 1
    With Sheets("shtMapping")
        .Cells(Rw, 1) = strAddress
        .Cells(Rw, 2) = val
        .Cells(Rw, 3) = dtmTime
    End With

End Sub

-

Fund Code   Subscription Rate   Redemption Rate
SGIS            0.16                     0.60
SPED            0.36                     0.40
SPEH            0.05                     0.12

so when I go and update subscription rate for SPED as 0.15 ,I need previous value 0.36 being captured and who had changed this existing value (username)


Solution

  • I created same headings in the mapping sheet from cells E to F and made it as hidden in the sheet .So when ever edit is pressed it copies to hidden and makes a compare to Audit sheet and replaces them,

    Sub CopyCurrentTable()

    Application.ScreenUpdating = False
    With shtMapping
        .Range("E4:G1000").ClearContents
        .Range("B4:D" & GetLastRow(shtMapping, "B", 4)).Copy
        .Range("E4").PasteSpecial xlPasteAll
        Application.CutCopyMode = False
    End With
    

    End Sub

    Sub SaveMapping()

    Dim bValidTable As Boolean: bValidTable = True
    Dim i As Long
    
    With shtMapping
        If .Shapes("shaEditMode").Visible Then
            .Unprotect g_sPassword
            .Range("B4:D103").Sort .Range("B4"), xlAscending
            For i = 4 To 103
                If .Range("B" & i).value = "" And .Range("C" & i).value = "" And .Range("D" & i).value = "" Then
                    Exit For
                ElseIf .Range("B" & i).value = "" Or .Range("C" & i).value = "" Or .Range("D" & i).value = "" Then
                    MsgBox "The table is missing critical information." & vbNewLine & "Please ensure all columns are populated in all rows of data.", vbCritical, "Error"
                    bValidTable = False
                    Exit For
                End If
    
                If .Range("B" & i).value = .Range("B" & i + 1) Then
                    MsgBox "The table contains duplicate Fund Codes." & vbNewLine & "Please ensure Fund Codes are unique and try again.", vbCritical, "Error"
                    bValidTable = False
                    Exit For
                End If
            Next i
            If bValidTable Then
                With .Range("B4:D103")
                    .Locked = True
                    .Interior.Color = vbWhite
                End With
                .Shapes("shaEditMode").Visible = False
    
                'Identify Changes and plot to Audit table
                Call LogAuditTrail
                Call OpenMain
                ThisWorkbook.Save
            End If
            .Protect g_sPassword
        Else
            Call OpenMain
        End If
    End With
    

    End Sub

    Sub LogAuditTrail()

    Dim colOld As Collection
    Dim colNew As Collection
    Dim objNew As ClsMapping
    Dim objOld As ClsMapping
    Set colOld = getMappingData("E")
    Set colNew = getMappingData("B")
    Dim sTS As String
    
    sTS = Format(Now, "dd-mmm-yyy hh:mm:ss")
    
    For Each objNew In colNew
        'Detect Items Changed
        If ItemIsInCollection(colOld, objNew.getKey) Then
            Set objOld = colOld(objNew.getKey)
            If objNew.isDifferent(objOld) Then
                Call PlotToAudit(objNew, objOld, sTS, "Change")
            End If
        Else
            'Detect Items Added
            Set objOld = New ClsMapping
            Call PlotToAudit(objNew, objOld, sTS, "New")
        End If
    Next objNew
    
    'Detect Items removed
    For Each objOld In colOld
        If Not ItemIsInCollection(colNew, objOld.getKey) Then
            Set objNew = New ClsMapping
            Call PlotToAudit(objNew, objOld, sTS, "Removed")
        End If
    Next objOld
    

    End Sub Sub PlotToAudit(obj1 As ClsMapping, obj2 As ClsMapping, sTS As String, sType As String)

    Dim lRow As Long
    lRow = shtAudit.Range("B1048576").End(xlUp).Row
    
    If lRow = 3 Then
        lRow = 5
    ElseIf lRow = 1048576 Then
        MsgBox "Audit sheet is full. Contact Support." & vbNewLine & "No audit trail will be saved", vbCritical, "ERROR"
        Exit Sub
    Else
        lRow = lRow + 1
    End If
    
    With shtAudit
        .Unprotect g_sPassword
        .Range("B" & lRow).value = Application.UserName & "(" & Environ("USERNAME") & ")"
        .Range("C" & lRow).value = sTS
        .Range("D" & lRow).value = sType
    
        Select Case sType
            Case "Removed"
                .Range("E" & lRow).value = ""
                .Range("F" & lRow).value = ""
                .Range("G" & lRow).value = ""
                .Range("H" & lRow).value = obj2.FundCode
                .Range("I" & lRow).value = obj2.Subs
                .Range("J" & lRow).value = obj2.Reds
            Case "New"
                .Range("E" & lRow).value = obj1.FundCode
                .Range("F" & lRow).value = obj1.Subs
                .Range("G" & lRow).value = obj1.Reds
                .Range("H" & lRow).value = ""
                .Range("I" & lRow).value = ""
                .Range("J" & lRow).value = ""
            Case "Change"
                .Range("E" & lRow).value = obj1.FundCode
                .Range("F" & lRow).value = obj1.Subs
                .Range("G" & lRow).value = obj1.Reds
                .Range("H" & lRow).value = obj2.FundCode
                .Range("I" & lRow).value = obj2.Subs
                .Range("J" & lRow).value = obj2.Reds
        End Select
        With .Range("B" & lRow & ":J" & lRow)
            .Interior.Color = vbWhite
            .Borders.LineStyle = xlContinuou
        End With
        .Protect g_sPassword
    End With
    

    End Sub