Files
Projektarbeit-MYP/backend/DOCS/UNDEFINED_JOBS_PROBLEM_LÖSUNG.md

9.1 KiB

Lösung: "undefined" Druckaufträge Problem

📋 Problem-Beschreibung

Das Mercedes-Benz MYP System zeigte bei Druckaufträgen häufig "undefined" Werte an, insbesondere:

  • Job-Name als "undefined"
  • Drucker-Name als "undefined"
  • Dauer als "undefined Min"
  • Benutzer-Informationen als "undefined"

Problem Screenshot

🔍 Ursachen-Analyse

1. Inkonsistente Datenfelder

Das Backend-Model Job.to_dict() gab andere Feldnamen zurück als das Frontend erwartete:

Backend gab zurück:

  • name (statt filename/title)
  • printer (Objekt statt printer_name)
  • user (Objekt statt user_name)

Frontend erwartete:

  • filename, title oder file_name
  • printer_name (String)
  • user_name (String)

2. Fehlende Dashboard-Daten

Die Dashboard-Funktion in app.py war leer und lud keine Daten:

@app.route("/dashboard")
@login_required
def dashboard():
    """Haupt-Dashboard"""
    return render_template("dashboard.html")  # Keine Daten!

3. JavaScript Null-Checks unvollständig

// Problematisch:
${job.filename || job.title || job.name || 'Unbekannter Job'}
// Wenn alle undefined → undefined wird angezeigt

Implementierte Lösung

1. Erweiterte Job.to_dict() Methode (models.py)

def to_dict(self) -> dict:
    # Grundlegende Job-Informationen
    result = {
        "id": self.id,
        "name": self.name,
        "description": self.description,
        # ... weitere Grundfelder
    }
    
    # Frontend-kompatible Felder hinzufügen
    result.update({
        # Alternative Namen für Frontend-Kompatibilität
        "title": self.name,
        "filename": self.name,
        "file_name": self.name,
        
        # Drucker-Informationen direkt verfügbar
        "printer_name": self.printer.name if self.printer else "Unbekannter Drucker",
        "printer_model": self.printer.model if self.printer else None,
        
        # Benutzer-Informationen direkt verfügbar
        "user_name": self.user.name if self.user else "Unbekannter Benutzer",
        "username": self.user.username if self.user else None,
        
        # Zeitstempel in deutschen Formaten
        "start_time": self.start_at.strftime('%d.%m.%Y %H:%M') if self.start_at else "Nicht festgelegt",
        "created_time": self.created_at.strftime('%d.%m.%Y %H:%M') if self.created_at else "Unbekannt",
        
        # Status-Text in Deutsch
        "status_text": self._get_status_text(self.status),
        
        # Berechnete Felder
        "progress": self._calculate_progress(),
        "remaining_minutes": self._calculate_remaining_minutes()
    })
    
    return result

def _get_status_text(self, status: str) -> str:
    """Wandelt englische Status-Codes in deutsche Texte um"""
    status_mapping = {
        'scheduled': 'Geplant',
        'pending': 'Wartend',
        'running': 'Läuft',
        'completed': 'Abgeschlossen',
        'failed': 'Fehlgeschlagen',
        # ... weitere Mappings
    }
    return status_mapping.get(status, status.title() if status else 'Unbekannt')

2. Vollständige Dashboard-Funktion (app.py)

@app.route("/dashboard")
@login_required
def dashboard():
    """Haupt-Dashboard mit vollständigen Daten für die Anzeige"""
    try:
        db_session = get_db_session()
        
        # Aktive Jobs laden
        active_jobs_query = db_session.query(Job).filter(
            Job.status.in_(['scheduled', 'running', 'printing', 'pending'])
        )
        
        if not current_user.is_admin:
            active_jobs_query = active_jobs_query.filter(Job.user_id == current_user.id)
        
        active_jobs = active_jobs_query.order_by(Job.created_at.desc()).limit(10).all()
        
        # Statistiken berechnen
        active_jobs_count = len(active_jobs)
        available_printers_count = len([p for p in printers if p.status in ['idle', 'ready']])
        success_rate = round((completed_jobs_count / total_jobs_count * 100), 1) if total_jobs_count > 0 else 0
        
        # Template-Daten mit Fallback-Werten
        template_data = {
            'active_jobs_count': active_jobs_count,
            'available_printers_count': available_printers_count,
            'total_jobs_count': total_jobs_count,
            'success_rate': success_rate,
            'active_jobs': dashboard_active_jobs,
            'printers': dashboard_printers,
            'activities': activities,
            # ... weitere Daten
        }
        
        return render_template("dashboard.html", **template_data)
        
    except Exception as e:
        # Fallback-Dashboard mit sicheren Standardwerten
        fallback_data = {
            'active_jobs_count': 0,
            'available_printers_count': 0,
            'total_jobs_count': 0,
            'success_rate': 0,
            'active_jobs': [],
            'printers': [],
            'activities': [],
            'error': f"Fehler beim Laden der Dashboard-Daten: {str(e)}"
        }
        return render_template("dashboard.html", **fallback_data)

3. Verbesserte JavaScript Null-Checks (global-refresh-functions.js)

// Verbesserte Feldermapping für Frontend-Kompatibilität
const jobName = job.name || job.title || job.filename || job.file_name || 'Unbekannter Job';
const printerName = job.printer_name || (job.printer?.name) || 'Unbekannter Drucker';
const userName = job.user_name || (job.user?.name) || 'Unbekannter Benutzer';
const statusText = job.status_text || job.status || 'Unbekannt';
const createdDate = job.created_time || (job.created_at ? new Date(job.created_at).toLocaleDateString('de-DE') : 'Unbekannt');
const progress = job.progress || 0;

// Sichere Job-Karten-Darstellung
return `
    <div class="job-card p-4 border rounded-lg bg-white dark:bg-slate-800 shadow-sm hover:shadow-md transition-shadow">
        <div class="flex justify-between items-start mb-3">
            <h3 class="font-semibold text-gray-900 dark:text-white text-lg">
                ${jobName}
            </h3>
            <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${getStatusBadgeClass(job.status)}">
                ${statusText}
            </span>
        </div>
        <div class="text-sm text-gray-600 dark:text-gray-400 space-y-1">
            <p><span class="font-medium">ID:</span> ${job.id || 'N/A'}</p>
            <p><span class="font-medium">Drucker:</span> ${printerName}</p>
            <p><span class="font-medium">Benutzer:</span> ${userName}</p>
            <p><span class="font-medium">Erstellt:</span> ${createdDate}</p>
            ${progress > 0 ? `<p><span class="font-medium">Fortschritt:</span> ${progress}%</p>` : ''}
        </div>
    </div>
`;

4. Status-Badge-Hilfsfunktion

function getStatusBadgeClass(status) {
    const statusClasses = {
        'scheduled': 'bg-blue-100 text-blue-800 dark:bg-blue-900/20 dark:text-blue-400',
        'pending': 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-400',
        'running': 'bg-green-100 text-green-800 dark:bg-green-900/20 dark:text-green-400',
        'completed': 'bg-gray-100 text-gray-800 dark:bg-gray-900/20 dark:text-gray-400',
        'failed': 'bg-red-100 text-red-800 dark:bg-red-900/20 dark:text-red-400',
        // ... weitere Status
    };
    
    return statusClasses[status] || 'bg-gray-100 text-gray-800 dark:bg-gray-900/20 dark:text-gray-400';
}

🎯 Ergebnis

Vorher:

  • Job-Name: undefined
  • Drucker: undefined
  • Dauer: undefined Min
  • Status: Englisch und unformatiert

Nachher:

  • Job-Name: "Druckjob vom 06.01.2025 14:30" (oder tatsächlicher Name)
  • Drucker: "Drucker 1" (tatsächlicher Drucker-Name)
  • Dauer: "45 Minuten" (korrekte Dauer)
  • Status: "Geplant", "Läuft", "Abgeschlossen" (deutsch, farbkodiert)
  • Fortschritt: Visuelle Fortschrittsbalken
  • Benutzer: Tatsächlicher Benutzername

🔧 Technische Details

Caching-Optimierung

  • Job-Daten werden für 3 Minuten gecacht
  • Cache wird bei Status-Änderungen invalidiert
  • Reduzierte Datenbankabfragen

Fehlerbehandlung

  • Fallback-Werte für alle kritischen Felder
  • Graceful Degradation bei Datenbankfehlern
  • Detaillierte Logging für Debugging

Performance

  • Eager Loading für Beziehungen (User, Printer)
  • Bulk-Operationen statt N+1 Queries
  • Minimierte Frontend-Datenübertragung

Tests durchgeführt

  1. Dashboard-Load: Alle Statistiken korrekt
  2. Job-Anzeige: Keine "undefined" Werte mehr
  3. Drucker-Status: Korrekte Namen und Status
  4. Benutzer-Info: Namen statt IDs angezeigt
  5. Status-Mapping: Deutsche Übersetzungen
  6. Fehlerbehandlung: Graceful Fallbacks

📚 Betroffene Dateien

  • models.py - Erweiterte Job.to_dict() Methode
  • app.py - Vollständige Dashboard-Funktion
  • static/js/global-refresh-functions.js - Verbesserte Frontend-Logik
  • blueprints/jobs.py - API-Endpunkte nutzen erweiterte Methoden
  • templates/dashboard.html - Template nutzt neue Datenfelder

🚀 Deployment

Die Änderungen sind vollständig rückwärtskompatibel und erfordern nur einen Neustart der Anwendung.

Status: VOLLSTÄNDIG IMPLEMENTIERT UND GETESTET