-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
Issue: "Läuft bald ab" berücksichtigt manuelle Serien nicht korrekt
🐛 Problem Description
Die "Läuft bald ab" Logik im Expiring Appointments Modul berücksichtigt manuelle Terminserien (ohne repeatUntil) nicht korrekt. Termine mit manuellen Zusatzterminen (additionals) werden möglicherweise falsch kategorisiert oder übersehen.
🔍 Current Behavior
Aktuelle Logik (aus Code-Analyse):
const getAppointmentStatus = (appointment: Appointment): 'active' | 'expiring' | 'expired' => {
const now = new Date()
let effectiveEndDate = null
// 1. Prüfe repeatUntil Datum
if (appointment.base.repeatUntil) {
effectiveEndDate = new Date(appointment.base.repeatUntil)
}
// 2. Falls kein repeatUntil, prüfe manuelle Zusatztermine
else if (appointment.base.additionals?.length > 0) {
// Nimmt das späteste Datum der Zusatztermine
const latestAdditional = appointment.base.additionals
.map(a => new Date(a.startDate))
.sort((a, b) => b.getTime() - a.getTime())[0]
effectiveEndDate = latestAdditional
}
// 3. Kein Enddatum = unbegrenzt aktiv
if (!effectiveEndDate) return 'active'
// 4. Status-Bestimmung
const daysUntilEnd = Math.ceil(
(effectiveEndDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)
)
if (effectiveEndDate < now) return 'expired'
if (daysUntilEnd <= 90) return 'expiring' // DAYS_TO_SHOW = 90
return 'active'
}⚠️ Identified Issues
1. Unvollständige Datenstruktur-Behandlung
- Code geht davon aus, dass
additionalsArray existiert undstartDateFelder hat - Keine Validierung der Datenstruktur
- Mögliche
undefinedodernullWerte nicht abgefangen
2. Falsche Datum-Interpretation
- Verwendet
startDateder Zusatztermine stattendDate - Bei mehrtägigen Terminen wird nur der Starttermin berücksichtigt
- Endzeit des letzten Termins wird ignoriert
3. Fehlende Edge-Case Behandlung
- Was passiert bei leeren
additionalsArrays? - Wie werden Termine ohne
repeatUntilUND ohneadditionalsbehandelt? - Keine Behandlung von ungültigen Datumsformaten
4. Inkonsistente Kategorisierung
- Manuelle Serien könnten als "unbegrenzt aktiv" klassifiziert werden
- Unterschiedliche Behandlung von automatischen vs. manuellen Serien
📊 Expected Behavior
Korrekte Logik sollte sein:
const getAppointmentStatus = (appointment: Appointment): 'active' | 'expiring' | 'expired' => {
const now = new Date()
let effectiveEndDate = null
// 1. Automatische Serie mit repeatUntil
if (appointment.base?.repeatUntil) {
effectiveEndDate = new Date(appointment.base.repeatUntil)
}
// 2. Manuelle Serie - letzter Zusatztermin
else if (appointment.base?.additionals?.length > 0) {
// Finde den spätesten Termin (Ende, nicht Start!)
const latestAdditional = appointment.base.additionals
.filter(a => a.startDate) // Nur gültige Termine
.map(a => {
// Verwende endDate falls vorhanden, sonst startDate
const date = a.endDate || a.startDate
return new Date(date)
})
.filter(date => !isNaN(date.getTime())) // Nur gültige Daten
.sort((a, b) => b.getTime() - a.getTime())[0]
effectiveEndDate = latestAdditional || null
}
// 3. Kein Enddatum ermittelbar
if (!effectiveEndDate) {
console.warn('Appointment has no determinable end date:', appointment.id)
return 'active' // Oder spezielle Kategorie "unknown"
}
// 4. Status-Bestimmung
const daysUntilEnd = Math.ceil(
(effectiveEndDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)
)
if (effectiveEndDate < now) return 'expired'
if (daysUntilEnd <= DAYS_TO_SHOW) return 'expiring'
return 'active'
}🧪 Test Cases
Test-Szenarien die überprüft werden sollten:
-
Automatische Serie:
repeatUntil: "2025-10-15"→ Status basierend auf diesem Datum
-
Manuelle Serie mit Zusatzterminen:
additionals: [{"startDate": "2025-10-01"}, {"startDate": "2025-10-15"}]- → Status basierend auf "2025-10-15"
-
Manuelle Serie mit End-Daten:
additionals: [{"startDate": "2025-10-01", "endDate": "2025-10-02"}]- → Status basierend auf "2025-10-02" (nicht "2025-10-01")
-
Edge Cases:
- Leeres
additionalsArray additionalsmit ungültigen Daten- Termine ohne
repeatUntilUND ohneadditionals
- Leeres
📁 Affected Files
src/components/expiring-appointments/ExpiringAppointmentsCard.vuesrc/components/expiring-appointments/ExpiringAppointmentsAdmin.vuesrc/services/churchtools.ts(möglicherweise)
🎯 Acceptance Criteria
✅ Definition of Done:
-
Korrekte Datum-Ermittlung:
- Manuelle Serien verwenden das Ende des letzten Zusatztermins
- Automatische Serien verwenden
repeatUntil - Robuste Behandlung von Edge Cases
-
Konsistente Kategorisierung:
- Alle Serien (automatisch/manuell) verwenden dieselbe 90-Tage-Regel
- Klare Behandlung von Terminen ohne ermittelbares Enddatum
-
Verbesserte Fehlerbehandlung:
- Logging für problematische Termine
- Graceful Fallbacks für ungültige Daten
-
Testing:
- Unit Tests für verschiedene Termintypen
- Manuelle Tests mit echten ChurchTools-Daten
🔧 Implementation Suggestions
1. Datenstruktur-Validierung:
const validateAppointmentData = (appointment: Appointment): boolean => {
return appointment?.base && (
appointment.base.repeatUntil ||
(appointment.base.additionals?.length > 0)
)
}2. Robuste Datum-Extraktion:
const extractEndDate = (additional: any): Date | null => {
const dateString = additional.endDate || additional.startDate
if (!dateString) return null
const date = new Date(dateString)
return isNaN(date.getTime()) ? null : date
}3. Logging für Debugging:
if (process.env.NODE_ENV === 'development') {
console.log('Appointment categorization:', {
id: appointment.id,
type: appointment.base?.repeatUntil ? 'automatic' : 'manual',
effectiveEndDate,
status: finalStatus
})
}🏷️ Labels
bug- Funktionalität arbeitet nicht wie erwartetenhancement- Verbesserung bestehender Funktionalitätexpiring-appointments- Betrifft das Expiring Appointments Modulpriority-medium- Wichtig für korrekte Funktionalität
🔗 Related
- Expiring Appointments Modul
- ChurchTools API Integration
- Date/Time Handling
Reporter: Development Team
Priority: Medium
Complexity: Medium
Estimated Effort: 4-6 hours
Metadata
Metadata
Assignees
Labels
No labels