Skip to content

"Läuft bald ab" berücksichtigt manuelle Serien nicht korrekt #6

@bwl21

Description

@bwl21

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 additionals Array existiert und startDate Felder hat
  • Keine Validierung der Datenstruktur
  • Mögliche undefined oder null Werte nicht abgefangen

2. Falsche Datum-Interpretation

  • Verwendet startDate der Zusatztermine statt endDate
  • 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 additionals Arrays?
  • Wie werden Termine ohne repeatUntil UND ohne additionals behandelt?
  • 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:

  1. Automatische Serie:

    • repeatUntil: "2025-10-15" → Status basierend auf diesem Datum
  2. Manuelle Serie mit Zusatzterminen:

    • additionals: [{"startDate": "2025-10-01"}, {"startDate": "2025-10-15"}]
    • → Status basierend auf "2025-10-15"
  3. Manuelle Serie mit End-Daten:

    • additionals: [{"startDate": "2025-10-01", "endDate": "2025-10-02"}]
    • → Status basierend auf "2025-10-02" (nicht "2025-10-01")
  4. Edge Cases:

    • Leeres additionals Array
    • additionals mit ungültigen Daten
    • Termine ohne repeatUntil UND ohne additionals

📁 Affected Files

  • src/components/expiring-appointments/ExpiringAppointmentsCard.vue
  • src/components/expiring-appointments/ExpiringAppointmentsAdmin.vue
  • src/services/churchtools.ts (möglicherweise)

🎯 Acceptance Criteria

✅ Definition of Done:

  1. Korrekte Datum-Ermittlung:

    • Manuelle Serien verwenden das Ende des letzten Zusatztermins
    • Automatische Serien verwenden repeatUntil
    • Robuste Behandlung von Edge Cases
  2. Konsistente Kategorisierung:

    • Alle Serien (automatisch/manuell) verwenden dieselbe 90-Tage-Regel
    • Klare Behandlung von Terminen ohne ermittelbares Enddatum
  3. Verbesserte Fehlerbehandlung:

    • Logging für problematische Termine
    • Graceful Fallbacks für ungültige Daten
  4. 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 erwartet
  • enhancement - Verbesserung bestehender Funktionalität
  • expiring-appointments - Betrifft das Expiring Appointments Modul
  • priority-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

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions