0

I have an Excel sheet that sends an email to people depending on their certification date.

Example of what this should look like.
enter image description here

It has been requested that if someone is listed with no certifications, they are sent an email to become certified or be taken off the list. I thought I figured out a solution.

Sub AutoMailerFinalSheet3()

Dim EApp As Object
Set EApp = CreateObject("Outlook.Application")
Dim EItem As Object
Dim RList As Range
Set RList = Range("C5", "BZ57")
Dim R As Range
Dim emptyCount As Integer
Dim Password As Variant
Dim sBodyOne As String
Dim sBodyTwo As String
Dim sWarnOne As String
Dim sWarnTwo As String
Dim RNames As Range, RName As Range
Set RNames = Range("C2", "P2")
Dim sOverdue As String

Password = Application.InputBox("Enter Password", "Password Protected")

Select Case Password
    Case Is = False
        '
    Case Is = "PPQE"
        emptyCount = 0
        For Each RName In RNames
            If isEmpty(RName) = False Then
        
            sOverdue = "due"
  
            For Each R In Intersect(RList, RName.EntireColumn)
                If isEmpty(R) = False Then
                    If (DateDiff("d", R.Value, Now)) >= 335 And (DateDiff("d", R.Value, Now)) < 365 Then
                            R.Interior.ColorIndex = 27 
                        sBodyOne = sBodyOne & vbNewLine & _
                            R.Offset(0, (-(R.Column - 1))) & ". You have " & (365 - (DateDiff("d", R.Value, Now))) & " days until it expires."
                        sWarnOne = vbNewLine & vbNewLine & "You are nearing expiration for the following equipment:" & vbNewLine
                    ElseIf (DateDiff("d", R.Value, Now)) > 365 Then
                        If (DateDiff("d", R.Value, Now)) > 425 Then
                            R.Interior.ColorIndex = 1 ]
                            sOverdue = "overdue" 'Change message to overdue
                            sBodyTwo = sBodyTwo & vbNewLine & _
                                R.Offset(0, (-(R.Column - 1))) & ". You are " & ((DateDiff("d", R.Value, Now)) - 365) & " days overdue for retraining."
                            sWarnTwo = vbNewLine & vbNewLine & "Your certification has expired with the following equipment:" & vbNewLine
                        Else
                            R.Interior.ColorIndex = 3 
                            sOverdue = "overdue" 
                            sBodyTwo = sBodyTwo & vbNewLine & _
                                R.Offset(0, (-(R.Column - 1))) & ". You are " & ((DateDiff("d", R.Value, Now)) - 365) & " days overdue for retraining. You have " & (Abs((DateDiff("d", R.Value, Now)) - 425)) & " days before a full retraining is required."
                            sWarnTwo = vbNewLine & vbNewLine & "Your certification has expired with the following equipment:" & vbNewLine
                        End If
                    ElseIf (DateDiff("d", R.Value, Now)) < 335 Then
                        R.Interior.ColorIndex = 10
                    
                    End If

                ElseIf isEmpty(R) = True Then
                    emptyCount = emptyCount + 1 'This counts every empty box, or cells without any certification
                
                End If
            Next
            End If
            
            If Not sBodyOne = "" Or Not sBodyTwo = "" Then
                Set EItem = EApp.CreateItem(0)
                With EItem
                  .To = RName.Offset(1, 0)
                  .Subject = "You're " & sOverdue & " for retraining and certification"
                  .body = "Hello, " & RName & vbNewLine & "This email is to remind you that your certification with Pilot Plant equipment is close to expiring, or has already expired." & sWarnOne & sBodyOne & sWarnTwo & sBodyTwo & vbNewLine & vbNewLine & "Contact ] for retraining."
                  .Display
                End With
                ElseIf emptyCount = 53 Then 'There are 53 pieces of equipment, so if they are all blank and there are no certification records, then it should send this email.
                Set EItem = EApp.CreateItem(0)
                With EItem
                    .To = RName.Offset(1, 0)
                    .Subject = "You are listed as an operator but have no certifications"
                    .body = "Hello, " & RName & vbNewLine & "You have been sent this email because you are listed as an operator, yet have no certifications with any equipment. Please reach out to schedule training, or to be removed from the operator list."
                End With
            End If
            
            If emptyCount > 0 Then
                MsgBox (emptyCount) 'My attempt at debugging and seeing the values.
            End If
            sBodyOne = vbNullString
            sBodyTwo = vbNullString
            sWarnOne = vbNullString
            sWarnTwo = vbNullString
            
        Next RName
        
        Set EApp = Nothing
        Set EItem = Nothing

    Case Else
        MsgBox "Incorrect Password"
End Select

End Sub

My solution is to count every empty box in the loop, adding 1 to a variable. When it reaches the end of the loop, if that variable is equal to 53 (the number of machines), then it should trigger that "If" statement and send, but it doesn't trigger. It still triggers normally for the ones that aren't empty.

I set up a text box that displays the variable's value, and it confirms that it properly counts to 53 for people who are completely uncertified, but the "If" statement doesn't trigger.

In the attached example screenshot, the code would count every blank cell under an operator's name, and compare it to the number of equipment there are. In this case, since Ally has 10 blank cells, and there are 10 machines, then the condition is met, and the email should trigger.

Community
  • 1
  • 1
Stoontly
  • 31
  • 5
  • 1
    I saw today a question with `IsEmpty` that looks similar to yours. https://stackoverflow.com/questions/76875175/unable-to-print-correct-message-based-on-conditional-if-elseif-else – Oran G. Utan Aug 10 '23 at 20:58
  • `If Len(R.Value)>0 Then` – Tim Williams Aug 10 '23 at 21:09
  • The ranges in your screenshot don't match the posted code? – Tim Williams Aug 10 '23 at 21:26
  • @TimWilliams Yes, my apologies, the screenshot is just an example to give an idea. In the actual document (which I am unable to share, unfortunately) the data starts in the appropriate cell (C5). Furthermore, the order is switched, where the equipment is vertical and the operators are listed horizontally. Again, my apologies for any confusion, the screenshot used is for an older prototype and was the only image I had around that didn't contain sensitive info. – Stoontly Aug 10 '23 at 22:45
  • 4
    You could maybe dummy-up a sheet which matches the code? It's much easier for folks to help with a visual guide... – Tim Williams Aug 10 '23 at 22:58
  • @TimWilliams You're absolutely right, my apologies. Find it attached shortly. – Stoontly Aug 11 '23 at 13:15

1 Answers1

0

Here's how I'd structure it - untested, and not fully complete (some of the messages need completing), but should be close to what you need.

Sub AutoMailerFinalSheet3()

    Dim EApp As Object, EItem As Object
    Dim Password As Variant
    Dim lastCol As Long, lastRow As Long, rngData As Range, data, rwNum As Long
    Dim nOK As Long, nClose As Long, nOver As Long, nOverFull As Long, colNum As Long, col As Range
    Dim sClose As String, sOver As String, sOverFull As String, ws As Worksheet
    Dim diff As Long, c As Range, equip, dt, sMsg As String, sSubj As String, sName As String, sEmail As String
    
    Set EApp = CreateObject("Outlook.Application")

    'check password and exit if incorrect
    Password = Application.InputBox("Enter Password", "Password Protected")
    If Password <> "PPQE" Then Exit Sub

    Set ws = ThisWorkbook.Worksheets("Certs") 'for example
    lastCol = ws.Cells(2, Columns.Count).End(xlToLeft).Column 'last "name" cell
    lastRow = ws.Cells(Rows.Count, "A").End(xlUp).row         'last "equipment" cell
    
    Set rngData = ws.Range("A2", ws.Cells(lastRow, lastCol))  'all the data
     
    For colNum = 3 To rngData.Columns.Count 'skip cols 1 and 2
        
        sName = rngData.Cells(1, colNum)    'name and email
        sEmail = rngData.Cells(2, colNum)
        
        nOK = 0: nClose = 0: nOver = 0           'reset counts and messages
        sClose = "": sOver = "": sOverFull = ""
        For rwNum = 3 To rngData.Rows.Count      'skip rows 1 and 2
            
            Set c = col.Cells(rwNum)        'date cell
            c.Interior.ColorIndex = xlNone  'clear any fill
            
            If Len(c.Value) > 0 Then
                equip = rngData.Cells(rwNum, 1).Value 'equipment
                dt = c.Value
                diff = DateDiff("d", dt, Now)    'only need to calc this once...
                
                'check the date difference, and increment counts and messages
                If diff < 335 Then
                    c.Interior.ColorIndex = 10
                    nOK = nOK + 1
                ElseIf diff >= 335 And diff < 365 Then
                    c.Interior.ColorIndex = 27
                    nClose = nClose + 1
                    sClose = sClose & vbCrLf & " --" & equip & " (" & (365 - diff) & " days remaining)"
                ElseIf diff >= 365 Then
                    If diff > 425 Then
                        c.Interior.ColorIndex = 1
                        nOverFull = nOverFull + 1
                        sOverFull = sOverFull & vbCrLf & " --" & equip & " rest here"
                    Else
                        c.Interior.ColorIndex = 3
                        nOver = nOver + 1
                        sOver = sOver & vbCrLf & " --" & equip & " rest here"
                    End If
                End If
            End If 'has a date
        Next rwNum
        
        'now check what message needs to get sent, if any
        sSubj = "" 'reset subject/message
        sMsg = ""
        
        If nOK + nClose + nOver + nOverFull = 0 Then 'no counts = no certs
            
            sSubj = "You are listed as an operator but have no certifications"
            sMsg = "Hello, " & sName & vbNewLine & "You have been sent this email because you " & _
                    " are listed as an operator, yet have no certifications with any equipment. " & _
                    "Please reach out to schedule training, or to be removed from the operator list."
            
        ElseIf nClose > 0 Or nOver > 0 Or nOverFull > 0 Then
            sSubj = "Review Equipment Certifications"
            sMsg = "Hello " & sName & vbCrLf
            
            If nClose > 0 Then
                sMsg = sMsg & vbCrLf & "The following certifications are close to expiring" & _
                       vbCrLf & sClose & vbCrLf
            End If
            
            If nOver > 0 Then
                'similar here
            End If
            
            If nOverFull > 0 Then
                'similar here
            End If
            
        End If 'sending any message?
        
        If Len(sSubj) > 0 Then
            'send the message....
        End If
   
   Next colNum 'next person
End Sub
Tim Williams
  • 154,628
  • 8
  • 97
  • 125