' 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 If Not DRYRUN Then 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 filterDatum As String filterDatum = Format(Date, "mm/dd/yyyy 12:00 AM") Set gefilterteItems = olItems.Restrict("[Start] >= '" & filterDatum & "'") Debug.Print "Gefilterte Einträge: " & gefilterteItems.Count On Error Resume Next Set logSheet = ThisWorkbook.Sheets("Gelöschte Termine") If logSheet Is Nothing Then Set logSheet = ThisWorkbook.Sheets.Add logSheet.Name = "Gelöschte Termine" logSheet.Range("A1:D1").Value = Array("Datum", "Startzeit", "Titel", "Kalender") End If On Error GoTo 0 End If Set ws = ThisWorkbook.Sheets(1) lastRow = ws.Cells(ws.Rows.Count, "B").End(xlUp).Row ReDim alreadyProcessed(1 To lastRow) For i = 2 To lastRow If alreadyProcessed(i) Then GoTo Weiter If ws.Cells(i, "B").Value < DateSerial(Year(Date), Month(Date), Day(Date)) Then ws.Cells(i, "M").Value = "übersprungen (Vergangenheit)" uebersprungenCount = uebersprungenCount + 1 GoTo Weiter End If If Not IsDate(ws.Cells(i, "B").Value) Or ws.Cells(i, "G").Value = "" Then ws.Cells(i, "M").Value = "übersprungen (kein Datum/kein Produkt)" uebersprungenCount = uebersprungenCount + 1 GoTo Weiter End If Set eintraege = New Collection veranstaltungsnummer = Trim(ws.Cells(i, "F").Value) produkt = Trim(ws.Cells(i, "G").Value) hinweis = Trim(ws.Cells(i, "L").Value) If InStr(hinweis, "Lehrgang: ") > 0 Then hinweis = Mid(hinweis, InStr(hinweis, "Lehrgang: ") + 10) End If titel = produkt & " - " & hinweis If Trim(titel) = "-" Or Trim(titel) = "- -" Or Trim(titel) = "" Then ws.Cells(i, "M").Value = "übersprungen (leerer Titel)" uebersprungenCount = uebersprungenCount + 1 GoTo Weiter End If ort = ws.Cells(i, "J").Value datum = ws.Cells(i, "B").Value eintraege.Add i alreadyProcessed(i) = True For j = i + 1 To lastRow If alreadyProcessed(j) Then GoTo SkipJ If Trim(ws.Cells(j, "F").Value) <> veranstaltungsnummer Then GoTo SkipJ If ws.Cells(j, "G").Value = "" Then GoTo SkipJ If Not IsDate(ws.Cells(j, "B").Value) Then GoTo SkipJ If ws.Cells(j, "B").Value - datum = 1 Or _ (Weekday(datum, vbMonday) = 5 And ws.Cells(j, "B").Value - datum = 3) Then eintraege.Add j alreadyProcessed(j) = True datum = ws.Cells(j, "B").Value Else Exit For End If SkipJ: Next j If eintraege.Count = 1 Then Dim idx As Variant: idx = eintraege(1) If IsDate(ws.Cells(idx, "C").Value) Then startzeit = TimeValue(ws.Cells(idx, "C").Value) Else ws.Cells(idx, "M").Value = "übersprungen (ungültige Startzeit)" GoTo Weiter End If If IsDate(ws.Cells(idx, "D").Value) Then endzeit = TimeValue(ws.Cells(idx, "D").Value) Else ws.Cells(idx, "M").Value = "übersprungen (ungültige Endzeit)" GoTo Weiter End If datum = DateValue(ws.Cells(idx, "B").Value) If DRYRUN Then ws.Cells(idx, "M").Value = "[Simulation] Einzel: " & titel Else Call OutlookEintragErstellen(selectedCalendar, gefilteteItems, datum, startzeit, endzeit, titel, ort, veranstaltungsnummer) ws.Cells(idx, "M").Value = titel End If ws.Cells(idx, "N").Value = IIf(DRYRUN, "(Simulation)", selectedCalendar.Name) erstelltCount = erstelltCount + 1 With ws.Cells(idx, "M").Interior: .Color = RGB(198, 239, 206): End With Else For Each idx In eintraege datum = ws.Cells(idx, "B").Value If Not DRYRUN Then Call OutlookEintragLoeschen(gefilteteItems, datum, titel, logSheet, selectedCalendar.Name) geloeschtCount = geloeschtCount + 1 End If Next idx If DRYRUN Then For Each idx In eintraege ws.Cells(idx, "M").Value = "[Simulation] Serie: " & titel ws.Cells(idx, "N").Value = "(Simulation)" serienCount = serienCount + 1 With ws.Cells(idx, "M").Interior: .Color = RGB(255, 235, 156): End With Next idx Else Dim appt As Object Set appt = selectedCalendar.Items.Add With appt .Start = ws.Cells(eintraege(1), "B").Value + ws.Cells(eintraege(1), "C").Value .End = ws.Cells(eintraege(1), "B").Value + ws.Cells(eintraege(1), "D").Value .Subject = titel .Location = ort .Body = "Veranstaltungsnummer: " & veranstaltungsnummer .BusyStatus = 2 .ReminderSet = False Dim pattern As Object Set pattern = .GetRecurrencePattern pattern.RecurrenceType = 0 pattern.Interval = 1 pattern.PatternStartDate = ws.Cells(eintraege(1), "B").Value pattern.PatternEndDate = ws.Cells(eintraege(eintraege.Count), "B").Value pattern.NoEndDate = False .Save End With For Each idx In eintraege ws.Cells(idx, "M").Value = "Serie: " & titel ws.Cells(idx, "N").Value = selectedCalendar.Name serienCount = serienCount + 1 With ws.Cells(idx, "M").Interior: .Color = RGB(255, 235, 156): End With Next idx End If End If Weiter: Next i MsgBox "Fertig in " & Format(Timer - startTime, "0.00") & " Sekunden." & vbCrLf & _ erstelltCount & " Einzeltermine erstellt" & vbCrLf & _ serienCount & " Serien-Einträge erstellt" & vbCrLf & _ geloeschtCount & " alte Termine gelöscht" & vbCrLf & _ uebersprungenCount & " Zeilen übersprungen", vbInformation End Sub ' Hilfsfunktion zum Erstellen eines Einzeltermins Sub OutlookEintragErstellen(ByVal selectedCalendar As Object, ByVal gefilteteItems As Object, ByVal datum As Date, ByVal startzeit As Date, ByVal endzeit As Date, ByVal titel As String, ByVal ort As String, ByVal veranstaltungsnummer As String) Dim item As Object, existingItem As Object Dim itemDate As Date Dim bodyText As String For Each existingItem In gefilteteItems If existingItem.Class = 26 Then ' nur AppointmentItems itemDate = Int(existingItem.Start) If itemDate = datum Then bodyText = "" & existingItem.Body If InStr(bodyText, veranstaltungsnummer) > 0 Then If existingItem.Subject <> titel Then Dim msg As VbMsgBoxResult msg = MsgBox("Ein Kalendereintrag mit derselben Veranstaltungsnummer existiert, aber der Titel unterscheidet sich:" & vbCrLf & _ "Bestehender Titel: " & existingItem.Subject & vbCrLf & _ "Neuer Titel: " & titel & vbCrLf & vbCrLf & _ "Trotzdem neuen Eintrag erstellen?", vbYesNo + vbExclamation, "Unstimmigkeit bei Titel") If msg = vbNo Then Exit Sub Else Debug.Print "Duplikat gefunden für Datum: " & datum & ", Titel: " & titel Exit Sub ' Duplikat mit gleichem Titel und Veranstaltungsnummer End If End If Debug.Print "Übersprungen wegen vorhandenem Eintrag: " & datum & " - " & titel Exit Sub End If End If Next Set item = selectedCalendar.Items.Add With item .Start = datum + startzeit .End = datum + endzeit .Subject = titel .Location = ort .Body = "Veranstaltungsnummer: " & veranstaltungsnummer .BusyStatus = 2 .ReminderSet = False .Save End With End Sub ' Hilfsfunktion zum Löschen vorhandener Einzeltermine mit gleichem Titel am gegebenen Datum Sub OutlookEintragLoeschen(ByVal gefilteteItems As Object, ByVal datum As Date, ByVal titel As String, ByVal logSheet As Worksheet, ByVal kalenderName As String) Dim item As Object Dim itemDate As Date For Each item In gefilteteItems If item.Class = 26 Then ' nur AppointmentItems itemDate = Int(item.Start) If itemDate = datum And item.Subject = titel Then logSheet.Cells(logSheet.Cells(Rows.Count, 1).End(xlUp).Row + 1, 1).Resize(1, 4).Value = _ Array(Format(item.Start, "dd.mm.yyyy"), Format(item.Start, "hh:nn"), titel, kalenderName) item.Delete Exit For End If End If Next End Sub