gistfile1.txt
· 11 KiB · Text
Raw
' Serien-Kalendereinträge aus Excel erstellen mit Serienlogik, Löschung alter Einträge, Logging, Laufzeitmessung, Zusammenfassung und Simulationsmodus
Sub SerienKalendereintraegeErstellen()
' Benutzer wird gefragt, ob Simulation gewünscht ist
Dim userResponse As VbMsgBoxResult
userResponse = MsgBox("Möchtest du eine Simulation durchführen (keine Einträge werden erstellt oder gelöscht)?", vbYesNo + vbQuestion, "Simulationsmodus")
Dim DRYRUN As Boolean
DRYRUN = (userResponse = vbYes) ' True = Simulation, False = Echtbetrieb
Dim olApp As Object, olNS As Object
Dim allCalendars As Collection, selectedCalendar As Object
Dim calendarNames() As String, selectedIndex As Variant
Dim olItems As Object, ws As Worksheet
Dim lastRow As Long, i As Long, j As Long, erstelltCount As Long, serienCount As Long, geloeschtCount As Long, uebersprungenCount As Long
Dim eintraege As Collection
Dim datum As Date, startzeit As Date, endzeit As Date
Dim produkt As String, hinweis As String, veranstaltungsnummer As String
Dim titel As String, ort As String
Dim alreadyProcessed() As Boolean
Dim startTime As Double
Dim logSheet As Worksheet
startTime = Timer
On Error Resume Next
Set olApp = GetObject(, "Outlook.Application")
If olApp Is Nothing Then Set olApp = CreateObject("Outlook.Application")
On Error GoTo 0
If olApp Is Nothing Then
MsgBox "Outlook konnte nicht gestartet werden.", vbCritical
Exit Sub
End If
Set olNS = olApp.GetNamespace("MAPI")
Set allCalendars = New Collection
Dim store As Object, folder As Object
For Each store In olNS.Folders
For Each folder In store.Folders
If folder.DefaultItemType = 1 Then allCalendars.Add folder
Next folder
Next store
ReDim calendarNames(1 To allCalendars.Count)
For i = 1 To allCalendars.Count
calendarNames(i) = allCalendars(i).Parent.Name & " – " & allCalendars(i).Name
Next i
selectedIndex = Application.InputBox("Wähle den Zielkalender aus (Zahl):" & vbCrLf & Join(calendarNames, vbCrLf), "Kalenderauswahl", Type:=1)
If Not IsNumeric(selectedIndex) Or selectedIndex < 1 Or selectedIndex > allCalendars.Count Then Exit Sub
Set selectedCalendar = allCalendars(selectedIndex)
MsgBox "Ausgewählter Kalender: " & selectedCalendar.Name, vbInformation, "Kalenderbestätigung"
Set olItems = selectedCalendar.Items
olItems.Sort "[Start]"
olItems.IncludeRecurrences = True
Dim gefilterteItems As Object
Dim filterStart As String
filterStart = "[Start] >= '" & Format(Date, "ddddd h:nn AMPM") & "'"
Set gefilterteItems = olItems.Restrict(filterStart)
Debug.Print "Kalender geladen: " & selectedCalendar.Name & ", " & gefilterteItems.Count & " gefilterte Einträge"
Set ws = ThisWorkbook.Sheets(1)
lastRow = ws.Cells(ws.Rows.Count, "B").End(xlUp).Row
ReDim alreadyProcessed(1 To lastRow)
Set eintraege = New Collection
For i = 2 To lastRow
Debug.Print "---"
Debug.Print "Verarbeite Zeile: " & i
Debug.Print "Datum: " & ws.Cells(i, "B").Text
Debug.Print "Startzeit: " & ws.Cells(i, "C").Text
Debug.Print "Endzeit: " & ws.Cells(i, "D").Text
Debug.Print "Produkt: " & ws.Cells(i, "G").Text
Debug.Print "Hinweis für Trainer: " & ws.Cells(i, "L").Text
Debug.Print "Veranstaltungsnummer: " & ws.Cells(i, "F").Text
Debug.Print "Ort: " & ws.Cells(i, "J").Text
If alreadyProcessed(i) Then GoTo Weiter
If Not IsDate(ws.Cells(i, "B").Value) Then
ws.Cells(i, "M").Value = "übersprungen (Datum fehlt)"
uebersprungenCount = uebersprungenCount + 1
GoTo Weiter
End If
If ws.Cells(i, "C").Value = "" Then
ws.Cells(i, "M").Value = "übersprungen (Startzeit fehlt)"
uebersprungenCount = uebersprungenCount + 1
GoTo Weiter
End If
If ws.Cells(i, "G").Value = "" Then
ws.Cells(i, "M").Value = "übersprungen (kein Produkt)"
uebersprungenCount = uebersprungenCount + 1
GoTo Weiter
End If
datum = DateValue(ws.Cells(i, "B").Value)
If IsDate(ws.Cells(i, "C").Value) Then
startzeit = TimeValue(ws.Cells(i, "C").Value)
Else
ws.Cells(i, "M").Value = "übersprungen (ungültige Startzeit)"
GoTo Weiter
End If
If IsDate(ws.Cells(i, "D").Value) Then
endzeit = TimeValue(ws.Cells(i, "D").Value)
Else
ws.Cells(i, "M").Value = "übersprungen (ungültige Endzeit)"
GoTo Weiter
End If
produkt = Trim(ws.Cells(i, "G").Value)
veranstaltungsnummer = Trim(ws.Cells(i, "F").Value)
hinweis = Trim(ws.Cells(i, "L").Value)
ort = Trim(ws.Cells(i, "J").Value)
If InStr(1, hinweis, "Lehrgang: ", vbTextCompare) > 0 Then
hinweis = Mid(hinweis, InStr(1, hinweis, "Lehrgang: ", vbTextCompare) + 10)
End If
titel = produkt & " - " & hinweis
If titel = " - " Or titel = "-" Then
ws.Cells(i, "M").Value = "übersprungen (kein gültiger Titel)"
GoTo Weiter
End If
' Duplikatprüfung: Wenn in Outlook bereits ein Termin mit Datum und Veranstaltungsnummer vorhanden ist
Dim skip As Boolean: skip = False
If Not DRYRUN Then
Dim existingItem As Object, itemDate As Date
For Each existingItem In gefilterteItems
If existingItem.Class = 26 Then
itemDate = Int(existingItem.Start)
If itemDate = datum Then
If InStr(existingItem.Body, veranstaltungsnummer) > 0 Then
If existingItem.Subject <> titel Then
Dim msg As VbMsgBoxResult
msg = MsgBox("Ein Eintrag mit gleicher Veranstaltungsnummer aber abweichendem Titel existiert: " & existingItem.Subject & vbCrLf & _
"Neuer Titel wäre: " & titel & vbCrLf & "Trotzdem ersetzen?", vbYesNo + vbExclamation)
If msg = vbNo Then skip = True
Else
skip = True
End If
End If
End If
End If
Next existingItem
End If
If skip Then
' Bestehenden Termin ggf. löschen
If Not DRYRUN Then
For Each existingItem In gefilterteItems
If existingItem.Class = 26 And Int(existingItem.Start) = datum Then
If InStr(existingItem.Body, veranstaltungsnummer) > 0 Then
existingItem.Delete
geloeschtCount = geloeschtCount + 1
Exit For
End If
End If
Next
End If
ws.Cells(i, "M").Value = "ersetzt (gelöscht + neu)"
GoTo Weiter
End If
' Erstellung des Outlook-Termins oder Simulation
If DRYRUN Then
ws.Cells(i, "M").Value = "(Simulation) " & titel
ws.Cells(i, "M").Interior.Color = RGB(200, 200, 200)
Else
Dim appt As Object
Set appt = olApp.CreateItem(1)
With appt
.Start = datum + startzeit
.End = datum + endzeit
.Subject = titel
.Location = ort
.Body = veranstaltungsnummer
.ReminderSet = False
.BusyStatus = 2
.Save
End With
ws.Cells(i, "M").Value = titel
erstelltCount = erstelltCount + 1
End If
alreadyProcessed(i) = True
' Serientermin-Erkennung: gleiche Veranstaltungsnummer an aufeinanderfolgenden Werktagen
Dim serieEndRow As Long: serieEndRow = i
Do While serieEndRow + 1 <= lastRow And Not alreadyProcessed(serieEndRow + 1)
Dim nextDatum As Date
If Not IsDate(ws.Cells(serieEndRow + 1, "B").Value) Then Exit Do
nextDatum = DateValue(ws.Cells(serieEndRow + 1, "B").Value)
If ws.Cells(serieEndRow + 1, "F").Value <> veranstaltungsnummer Then Exit Do
If Weekday(datum, vbMonday) = 5 Then ' Freitag
If DateDiff("d", datum, nextDatum) <> 3 Then Exit Do ' Freitag → Montag
Else
If DateDiff("d", datum, nextDatum) <> 1 Then Exit Do
End If
If ws.Cells(serieEndRow + 1, "G").Value = "" Then Exit Do
serieEndRow = serieEndRow + 1
Loop
If serieEndRow > i Then
' Serien-Eintrag
If Not DRYRUN Then
Dim recurrenceAppt As Object
Set recurrenceAppt = olApp.CreateItem(1)
With recurrenceAppt
.Start = datum + startzeit
.End = datum + endzeit
.Subject = titel
.Location = ort
.Body = veranstaltungsnummer
.ReminderSet = False
.BusyStatus = 2
.Save
Dim pattern
Set pattern = .GetRecurrencePattern
pattern.RecurrenceType = 1 ' daily
pattern.PatternStartDate = datum
pattern.Occurrences = serieEndRow - i + 1
.Save
End With
For j = i To serieEndRow
alreadyProcessed(j) = True
ws.Cells(j, "M").Value = titel & " (Serie)"
Next j
serienCount = serienCount + 1
GoTo Weiter
Else
For j = i To serieEndRow
alreadyProcessed(j) = True
ws.Cells(j, "M").Value = "(Simulation) " & titel & " (Serie)"
ws.Cells(j, "M").Interior.Color = RGB(180, 180, 180)
Next j
serienCount = serienCount + 1
GoTo Weiter
End If
End If
Weiter:
Next i
Dim elapsedTime As Double
elapsedTime = Timer - startTime
MsgBox "Fertig. " & erstelltCount & " Termine erstellt, " & serienCount & " Serientermine erstellt, " & geloeschtCount & " ersetzt, " & uebersprungenCount & " übersprungen." & vbCrLf & _
"Laufzeit: " & Format(elapsedTime, "0.00") & " Sekunden", vbInformation
End Sub
| 1 | ' Serien-Kalendereinträge aus Excel erstellen mit Serienlogik, Löschung alter Einträge, Logging, Laufzeitmessung, Zusammenfassung und Simulationsmodus |
| 2 | |
| 3 | Sub SerienKalendereintraegeErstellen() |
| 4 | ' Benutzer wird gefragt, ob Simulation gewünscht ist |
| 5 | Dim userResponse As VbMsgBoxResult |
| 6 | userResponse = MsgBox("Möchtest du eine Simulation durchführen (keine Einträge werden erstellt oder gelöscht)?", vbYesNo + vbQuestion, "Simulationsmodus") |
| 7 | Dim DRYRUN As Boolean |
| 8 | DRYRUN = (userResponse = vbYes) ' True = Simulation, False = Echtbetrieb |
| 9 | |
| 10 | Dim olApp As Object, olNS As Object |
| 11 | Dim allCalendars As Collection, selectedCalendar As Object |
| 12 | Dim calendarNames() As String, selectedIndex As Variant |
| 13 | Dim olItems As Object, ws As Worksheet |
| 14 | Dim lastRow As Long, i As Long, j As Long, erstelltCount As Long, serienCount As Long, geloeschtCount As Long, uebersprungenCount As Long |
| 15 | Dim eintraege As Collection |
| 16 | Dim datum As Date, startzeit As Date, endzeit As Date |
| 17 | Dim produkt As String, hinweis As String, veranstaltungsnummer As String |
| 18 | Dim titel As String, ort As String |
| 19 | Dim alreadyProcessed() As Boolean |
| 20 | Dim startTime As Double |
| 21 | Dim logSheet As Worksheet |
| 22 | |
| 23 | startTime = Timer |
| 24 | |
| 25 | On Error Resume Next |
| 26 | Set olApp = GetObject(, "Outlook.Application") |
| 27 | If olApp Is Nothing Then Set olApp = CreateObject("Outlook.Application") |
| 28 | On Error GoTo 0 |
| 29 | If olApp Is Nothing Then |
| 30 | MsgBox "Outlook konnte nicht gestartet werden.", vbCritical |
| 31 | Exit Sub |
| 32 | End If |
| 33 | Set olNS = olApp.GetNamespace("MAPI") |
| 34 | Set allCalendars = New Collection |
| 35 | |
| 36 | Dim store As Object, folder As Object |
| 37 | For Each store In olNS.Folders |
| 38 | For Each folder In store.Folders |
| 39 | If folder.DefaultItemType = 1 Then allCalendars.Add folder |
| 40 | Next folder |
| 41 | Next store |
| 42 | |
| 43 | ReDim calendarNames(1 To allCalendars.Count) |
| 44 | For i = 1 To allCalendars.Count |
| 45 | calendarNames(i) = allCalendars(i).Parent.Name & " – " & allCalendars(i).Name |
| 46 | Next i |
| 47 | selectedIndex = Application.InputBox("Wähle den Zielkalender aus (Zahl):" & vbCrLf & Join(calendarNames, vbCrLf), "Kalenderauswahl", Type:=1) |
| 48 | If Not IsNumeric(selectedIndex) Or selectedIndex < 1 Or selectedIndex > allCalendars.Count Then Exit Sub |
| 49 | |
| 50 | Set selectedCalendar = allCalendars(selectedIndex) |
| 51 | MsgBox "Ausgewählter Kalender: " & selectedCalendar.Name, vbInformation, "Kalenderbestätigung" |
| 52 | Set olItems = selectedCalendar.Items |
| 53 | olItems.Sort "[Start]" |
| 54 | olItems.IncludeRecurrences = True |
| 55 | |
| 56 | Dim gefilterteItems As Object |
| 57 | Dim filterStart As String |
| 58 | filterStart = "[Start] >= '" & Format(Date, "ddddd h:nn AMPM") & "'" |
| 59 | Set gefilterteItems = olItems.Restrict(filterStart) |
| 60 | |
| 61 | Debug.Print "Kalender geladen: " & selectedCalendar.Name & ", " & gefilterteItems.Count & " gefilterte Einträge" |
| 62 | Set ws = ThisWorkbook.Sheets(1) |
| 63 | lastRow = ws.Cells(ws.Rows.Count, "B").End(xlUp).Row |
| 64 | ReDim alreadyProcessed(1 To lastRow) |
| 65 | |
| 66 | Set eintraege = New Collection |
| 67 | |
| 68 | For i = 2 To lastRow |
| 69 | Debug.Print "---" |
| 70 | Debug.Print "Verarbeite Zeile: " & i |
| 71 | Debug.Print "Datum: " & ws.Cells(i, "B").Text |
| 72 | Debug.Print "Startzeit: " & ws.Cells(i, "C").Text |
| 73 | Debug.Print "Endzeit: " & ws.Cells(i, "D").Text |
| 74 | Debug.Print "Produkt: " & ws.Cells(i, "G").Text |
| 75 | Debug.Print "Hinweis für Trainer: " & ws.Cells(i, "L").Text |
| 76 | Debug.Print "Veranstaltungsnummer: " & ws.Cells(i, "F").Text |
| 77 | Debug.Print "Ort: " & ws.Cells(i, "J").Text |
| 78 | If alreadyProcessed(i) Then GoTo Weiter |
| 79 | If Not IsDate(ws.Cells(i, "B").Value) Then |
| 80 | ws.Cells(i, "M").Value = "übersprungen (Datum fehlt)" |
| 81 | uebersprungenCount = uebersprungenCount + 1 |
| 82 | GoTo Weiter |
| 83 | End If |
| 84 | If ws.Cells(i, "C").Value = "" Then |
| 85 | ws.Cells(i, "M").Value = "übersprungen (Startzeit fehlt)" |
| 86 | uebersprungenCount = uebersprungenCount + 1 |
| 87 | GoTo Weiter |
| 88 | End If |
| 89 | If ws.Cells(i, "G").Value = "" Then |
| 90 | ws.Cells(i, "M").Value = "übersprungen (kein Produkt)" |
| 91 | uebersprungenCount = uebersprungenCount + 1 |
| 92 | GoTo Weiter |
| 93 | End If |
| 94 | |
| 95 | datum = DateValue(ws.Cells(i, "B").Value) |
| 96 | If IsDate(ws.Cells(i, "C").Value) Then |
| 97 | startzeit = TimeValue(ws.Cells(i, "C").Value) |
| 98 | Else |
| 99 | ws.Cells(i, "M").Value = "übersprungen (ungültige Startzeit)" |
| 100 | GoTo Weiter |
| 101 | End If |
| 102 | If IsDate(ws.Cells(i, "D").Value) Then |
| 103 | endzeit = TimeValue(ws.Cells(i, "D").Value) |
| 104 | Else |
| 105 | ws.Cells(i, "M").Value = "übersprungen (ungültige Endzeit)" |
| 106 | GoTo Weiter |
| 107 | End If |
| 108 | |
| 109 | produkt = Trim(ws.Cells(i, "G").Value) |
| 110 | veranstaltungsnummer = Trim(ws.Cells(i, "F").Value) |
| 111 | hinweis = Trim(ws.Cells(i, "L").Value) |
| 112 | ort = Trim(ws.Cells(i, "J").Value) |
| 113 | |
| 114 | If InStr(1, hinweis, "Lehrgang: ", vbTextCompare) > 0 Then |
| 115 | hinweis = Mid(hinweis, InStr(1, hinweis, "Lehrgang: ", vbTextCompare) + 10) |
| 116 | End If |
| 117 | titel = produkt & " - " & hinweis |
| 118 | If titel = " - " Or titel = "-" Then |
| 119 | ws.Cells(i, "M").Value = "übersprungen (kein gültiger Titel)" |
| 120 | GoTo Weiter |
| 121 | End If |
| 122 | |
| 123 | ' Duplikatprüfung: Wenn in Outlook bereits ein Termin mit Datum und Veranstaltungsnummer vorhanden ist |
| 124 | Dim skip As Boolean: skip = False |
| 125 | If Not DRYRUN Then |
| 126 | Dim existingItem As Object, itemDate As Date |
| 127 | For Each existingItem In gefilterteItems |
| 128 | If existingItem.Class = 26 Then |
| 129 | itemDate = Int(existingItem.Start) |
| 130 | If itemDate = datum Then |
| 131 | If InStr(existingItem.Body, veranstaltungsnummer) > 0 Then |
| 132 | If existingItem.Subject <> titel Then |
| 133 | Dim msg As VbMsgBoxResult |
| 134 | msg = MsgBox("Ein Eintrag mit gleicher Veranstaltungsnummer aber abweichendem Titel existiert: " & existingItem.Subject & vbCrLf & _ |
| 135 | "Neuer Titel wäre: " & titel & vbCrLf & "Trotzdem ersetzen?", vbYesNo + vbExclamation) |
| 136 | If msg = vbNo Then skip = True |
| 137 | Else |
| 138 | skip = True |
| 139 | End If |
| 140 | End If |
| 141 | End If |
| 142 | End If |
| 143 | Next existingItem |
| 144 | End If |
| 145 | If skip Then |
| 146 | ' Bestehenden Termin ggf. löschen |
| 147 | If Not DRYRUN Then |
| 148 | For Each existingItem In gefilterteItems |
| 149 | If existingItem.Class = 26 And Int(existingItem.Start) = datum Then |
| 150 | If InStr(existingItem.Body, veranstaltungsnummer) > 0 Then |
| 151 | existingItem.Delete |
| 152 | geloeschtCount = geloeschtCount + 1 |
| 153 | Exit For |
| 154 | End If |
| 155 | End If |
| 156 | Next |
| 157 | End If |
| 158 | ws.Cells(i, "M").Value = "ersetzt (gelöscht + neu)" |
| 159 | GoTo Weiter |
| 160 | End If |
| 161 | |
| 162 | ' Erstellung des Outlook-Termins oder Simulation |
| 163 | If DRYRUN Then |
| 164 | ws.Cells(i, "M").Value = "(Simulation) " & titel |
| 165 | ws.Cells(i, "M").Interior.Color = RGB(200, 200, 200) |
| 166 | Else |
| 167 | Dim appt As Object |
| 168 | Set appt = olApp.CreateItem(1) |
| 169 | With appt |
| 170 | .Start = datum + startzeit |
| 171 | .End = datum + endzeit |
| 172 | .Subject = titel |
| 173 | .Location = ort |
| 174 | .Body = veranstaltungsnummer |
| 175 | .ReminderSet = False |
| 176 | .BusyStatus = 2 |
| 177 | .Save |
| 178 | End With |
| 179 | ws.Cells(i, "M").Value = titel |
| 180 | erstelltCount = erstelltCount + 1 |
| 181 | End If |
| 182 | alreadyProcessed(i) = True |
| 183 | |
| 184 | ' Serientermin-Erkennung: gleiche Veranstaltungsnummer an aufeinanderfolgenden Werktagen |
| 185 | Dim serieEndRow As Long: serieEndRow = i |
| 186 | Do While serieEndRow + 1 <= lastRow And Not alreadyProcessed(serieEndRow + 1) |
| 187 | Dim nextDatum As Date |
| 188 | If Not IsDate(ws.Cells(serieEndRow + 1, "B").Value) Then Exit Do |
| 189 | nextDatum = DateValue(ws.Cells(serieEndRow + 1, "B").Value) |
| 190 | If ws.Cells(serieEndRow + 1, "F").Value <> veranstaltungsnummer Then Exit Do |
| 191 | If Weekday(datum, vbMonday) = 5 Then ' Freitag |
| 192 | If DateDiff("d", datum, nextDatum) <> 3 Then Exit Do ' Freitag → Montag |
| 193 | Else |
| 194 | If DateDiff("d", datum, nextDatum) <> 1 Then Exit Do |
| 195 | End If |
| 196 | If ws.Cells(serieEndRow + 1, "G").Value = "" Then Exit Do |
| 197 | serieEndRow = serieEndRow + 1 |
| 198 | Loop |
| 199 | |
| 200 | If serieEndRow > i Then |
| 201 | ' Serien-Eintrag |
| 202 | If Not DRYRUN Then |
| 203 | Dim recurrenceAppt As Object |
| 204 | Set recurrenceAppt = olApp.CreateItem(1) |
| 205 | With recurrenceAppt |
| 206 | .Start = datum + startzeit |
| 207 | .End = datum + endzeit |
| 208 | .Subject = titel |
| 209 | .Location = ort |
| 210 | .Body = veranstaltungsnummer |
| 211 | .ReminderSet = False |
| 212 | .BusyStatus = 2 |
| 213 | .Save |
| 214 | Dim pattern |
| 215 | Set pattern = .GetRecurrencePattern |
| 216 | pattern.RecurrenceType = 1 ' daily |
| 217 | pattern.PatternStartDate = datum |
| 218 | pattern.Occurrences = serieEndRow - i + 1 |
| 219 | .Save |
| 220 | End With |
| 221 | For j = i To serieEndRow |
| 222 | alreadyProcessed(j) = True |
| 223 | ws.Cells(j, "M").Value = titel & " (Serie)" |
| 224 | Next j |
| 225 | serienCount = serienCount + 1 |
| 226 | GoTo Weiter |
| 227 | Else |
| 228 | For j = i To serieEndRow |
| 229 | alreadyProcessed(j) = True |
| 230 | ws.Cells(j, "M").Value = "(Simulation) " & titel & " (Serie)" |
| 231 | ws.Cells(j, "M").Interior.Color = RGB(180, 180, 180) |
| 232 | Next j |
| 233 | serienCount = serienCount + 1 |
| 234 | GoTo Weiter |
| 235 | End If |
| 236 | End If |
| 237 | |
| 238 | Weiter: |
| 239 | Next i |
| 240 | |
| 241 | Dim elapsedTime As Double |
| 242 | elapsedTime = Timer - startTime |
| 243 | MsgBox "Fertig. " & erstelltCount & " Termine erstellt, " & serienCount & " Serientermine erstellt, " & geloeschtCount & " ersetzt, " & uebersprungenCount & " übersprungen." & vbCrLf & _ |
| 244 | "Laufzeit: " & Format(elapsedTime, "0.00") & " Sekunden", vbInformation |
| 245 | End Sub |
| 246 |