Stundenpakete ohne verlässlichen Saldo zu verkaufen heißt, im Dunkeln zu arbeiten: Der Kunde stellt die Rechnung infrage, der Techniker weiß nicht, wie viel noch übrig ist, und der Monatsabschluss wird zur Tabellen-Archäologie. Das Modul Contract Hours von NexTool löst dieses Problem direkt in GLPI, indem es die Zeit in der Zeitleiste des Tickets misst und sie vom richtigen Vertrag abbucht. Dieser Leitfaden zeigt die Konfiguration, die Felder, die am häufigsten verwirren, und den Bedienfehler, der die gesamte Abrechnung blockiert.
Was natives GLPI nicht bietet
Das Feld Dauer der Aufgabe (in Sekunden in der Spalte actiontime gespeichert) erfasst Zeit, kennt aber weder Vertrag noch Kontingent oder Saldo. Sie tippen die Minuten von Hand ein, ohne Timer, ohne abrechenbare Rundung und ohne Antwort auf die einzige Frage, die der Kunde jeden Monat stellt: „Wie viel habe ich schon verbraucht und wie viel bleibt noch?“ Contract Hours legt diese Ebene über ein natives Feld, ohne es zu ersetzen.
Wie die Zeit erfasst wird
Der Techniker steuert einen Timer direkt in der Zeitleiste des Tickets:
- Start beginnt die Zählung; ein schwebendes Badge bleibt auf allen GLPI-Seiten sichtbar, solange eine Messung läuft.
- Pause / Resume ziehen Unterbrechungen (Besprechung, Mittagspause) ab, ohne die bereits angesammelte Zeit zu verlieren.
- Stop rundet die Zeit, legt eine private TicketTask an und bucht sie vom verknüpften Vertrag ab.
Wird ein Ticket gelöst oder geschlossen, stoppt ein Hook den Timer automatisch (Auto-Stop). Dieses Detail verhindert, dass ein vergessener Timer die ganze Nacht läuft und den Verbrauch aufbläht.
Schritt für Schritt: einen Vertrag konfigurieren
- Installieren und aktivieren Sie das Modul unter NexTool -> Module -> Contract Hours. Die Installation legt die Tabellen und die Übersichts-VIEW an und registriert drei CronTasks (billing, cleanup, reconcile).
- Legen Sie die abrechenbare Mindestzeit in den Einstellungen fest (Standard 15 Min.). Die Rundung erfolgt in zwei Schritten: zuerst auf ein Vielfaches der Mindestzeit, dann auf ein Vielfaches von 5 (Kompatibilität mit dem
actiontimevon GLPI). - Erstellen Sie den Vertrag in der Registerkarte Stundenverträge: Name, Einheit (1:1-Beziehung), Gesamtstunden, Abrechnungstag, Periodizität und Warnschwelle.
- Konfigurieren Sie die Kriterien in der Registerkarte Bedingungen: die Gruppen und/oder ITIL-Kategorien, über die ein Ticket diesem Vertrag zugeordnet wird.
- Passen Sie die Sichtbarkeit an in der Registerkarte Sichtbarkeit: Benutzer, Profile und Gruppen, die den Vertrag im Kunden-Dashboard sehen. Eine leere Liste bedeutet: sichtbar für alle mit Leseberechtigung.
Der typische Fehler hier: Das Feld „Gesamtstunden“ wird in MINUTEN gespeichert. Wer „40“ eingibt und dabei an 40 Stunden denkt, legt in Wirklichkeit einen Vertrag über 40 Minuten an und sieht den Saldo schon beim ersten Ticket überlaufen. Für 40 Stunden geben Sie 2400 ein.
Die Zuordnungsregel ist UND, nicht ODER
Die Entscheidung, wann ein Ticket zu einem Vertrag gehört, ist der Punkt, an dem wir die meisten Fehlkonfigurationen sehen. Die Logik kombiniert die Einheit (immer Pflicht, 1:1) mit optionalen Kriterien für Gruppe und Kategorie:
| Kriterien im Vertrag | Angewandte Regel | Ein Ticket fällt in den Vertrag, wenn |
|---|---|---|
| Keine | Nur die Einheit | Immer (es genügt, zur Einheit des Vertrags zu gehören) |
| Nur Gruppen | Zugehörigkeit innerhalb des Typs | Eine zugewiesene Gruppe steht auf der Liste des Vertrags |
| Nur Kategorien | Zugehörigkeit innerhalb des Typs | Die ITIL-Kategorie ist in den Regeln des Vertrags enthalten |
| Gruppen UND Kategorien | AND zwischen den Typen | Gruppe auf der Liste UND Kategorie in den Regeln (beides) |
Mit anderen Worten: Sind Gruppe UND Kategorie ausgefüllt, fällt ein Ticket nur dann in den Vertrag, wenn beide übereinstimmen. Wer beides konfiguriert und ein „ODER“-Verhalten erwartet, schiebt damit die Hälfte der Tickets auf die Karte „Ohne Vertrag“.
actiontime ist die maßgebliche Quelle
Ab Version 3.4.2 behandelt das Modul den actiontime der TicketTask als primäre Quelle. Der billable_time des Timers wird über drei Ebenen synchron gehalten: den Hook onTicketTaskUpdated (in Echtzeit, wenn Sie die Aufgabe im nativen GLPI bearbeiten), den Cron reconcile (alle 4 Std.) und die Schaltfläche „Verträge neu berechnen“. In der Praxis wirkt sich eine Änderung der Aufgabendauer direkt in GLPI auf den Vertragssaldo aus – sofern der Cron läuft.
Der Cron muss im externen Modus laufen
Hier liegt der Bedienfehler, der alles blockiert. Contract Hours hängt von drei CronTasks ab: billing (schließt den Zyklus ab und setzt den Verbrauch zurück), cleanup (schließt verwaiste Timer) und reconcile (synchronisiert und ordnet neu zu). Sie laufen nur, wenn die automatischen Aktionen von GLPI im externen Modus (CLI) sind. Im GLPI-Modus (durch Webzugriffe ausgelöst) kann eine Umgebung mit wenig Verkehr tagelang ohne Abschluss des Abrechnungszyklus bleiben, und vergessene Timer summieren Phantomstunden.
Stellen Sie sicher, dass der System-Cron auf den Ausführer der automatischen Aktionen von GLPI zeigt:
# /etc/cron.d/glpi - fires GLPI automatic actions every minute (external mode)
# Adjust the path to your install (in GLPI 11 the document root is public/)
* * * * * www-data /usr/bin/php /var/www/glpi/front/cron.php >/dev/null 2>&1
Prüfen Sie anschließend, ob die Aufgaben des Moduls geplant sind, im externen Modus laufen und kürzlich ausgeführt wurden:
-- State of the 3 Contract Hours CronTasks
SELECT name, frequency, mode, state, lastrun
FROM glpi_crontasks
WHERE itemtype = 'PluginNextoolContracthoursCron';
-- mode=2 (external/CLI), state=1 (scheduled) and a recent lastrun = healthy.
Diagnose bei abweichendem Saldo
Im Support von Kundenumgebungen wiederholt sich ein Muster: Der Vertrag wird korrekt angelegt, die ersten Tickets buchen richtig ab, und drei Wochen später „hängt“ der Saldo. In fast allen Fällen ist die Ursache dieselbe – die automatischen Aktionen liefen im Webmodus statt im externen CLI-Modus. Ohne externen Cron schließt billing nie den Zyklus ab, reconcile synchronisiert nie die Änderungen an der Aufgabe, und cleanup beendet nie die verwaisten Timer von jemandem, der am Freitag das Stop vergessen hat. Deshalb ist die erste Abfrage, die wir bei einer Contract-Hours-Diagnose ausführen, die auf glpi_crontasks und nicht die zum Saldo: Ist der lastrun der drei Aufgaben nicht aktuell, liegt es nicht am Modul, sondern an der GLPI-Infrastruktur.
Ist der Cron bestätigt, ist der zweite Verdächtige ein billable_time, der nach einer rückwirkenden Bearbeitung nicht mehr mit dem actiontime übereinstimmt. Messen Sie die Abweichung, bevor Sie blind neu berechnen:
-- Timers whose billed time drifted from the task actiontime (source of truth)
SELECT t.id, t.tickets_id,
t.billable_time/60 AS billed_min,
tt.actiontime/60 AS task_min,
(t.billable_time - tt.actiontime) AS diff_seconds
FROM glpi_plugin_nextool_contracthours_timers t
JOIN glpi_tickettasks tt ON tt.id = t.tickettasks_id
WHERE t.status = 'stopped'
AND t.billable_time != tt.actiontime
LIMIT 20;
Gibt es Abweichungen, führt die Schaltfläche „Verträge neu berechnen“ (Registerkarte Daten) die Synchronisierung aus und berechnet den Verbrauch neu. Zur Prüfung des Saldos – denken Sie daran, dass die Felder in Minuten vorliegen:
-- Balance per active contract (values in minutes, converted to hours)
SELECT name, entities_id,
total_hours/60 AS quota_h,
used_hours/60 AS used_h,
(total_hours - used_hours)/60 AS balance_h
FROM glpi_plugin_nextool_contracthours_contracts
WHERE is_active = 1
ORDER BY balance_h;
Audit, Warnungen und Kulanz
Jede rückwirkende Zeitänderung wird in der Registerkarte Logs protokolliert – wer sie vorgenommen hat, wann und welcher Wert vorher galt. Diese Rückverfolgbarkeit schätzen Sie, wenn der Kunde eine gebuchte Stunde anficht. Die Warnungen werden nach Verbrauchsanteil ausgelöst (Standardschwelle 80 %) sowie bei zwei Vertragsbedingungen: abgelaufen (Enddatum in der Vergangenheit) und Stunden überschritten. Jede Bedingung lässt sich als „nichts tun“, „Warnung“ (gelbes, schließbares Popup) oder „Sperre“ konfigurieren. Ein feines Detail: Die rote Sperre greift nur beim Erstellen eines Tickets über den Helpdesk (ServiceCatalog); ein bereits offenes Ticket wird nie gesperrt, sondern erhält nur die Warnung. Seit Version 3.6 gibt es zudem den Schalter „nicht abrechenbar“ (Kulanz): Die Zeit wird erfasst, aber nicht vom Saldo abgebucht – nützlich für Einsätze, die Sie dokumentieren möchten, ohne sie vom Kontingent des Kunden abzuziehen.
Ticketstunden in eine belastbare Abrechnung zu verwandeln – mit Saldo, Auszug und einem Dashboard, das der Kunde versteht – ist genau das, was das Modul Contract Hours des NexTool-Plugins leistet. Wenn Sie GLPI betreuen und den Monat noch in der Tabelle abschließen, sprechen Sie mit uns.
Geprüft vom Team von NexTool Solutions.