Stundenkontingente pro Vertrag in GLPI mit Contract Hours erfassen

Technischer Leitfaden zur Konfiguration von Contract Hours in GLPI: Timer in der Zeitleiste, Verträge pro Einheit mit Zuordnung über Gruppe UND Kategorie, abrechenbare Rundung, Saldo in Minuten und der externe Cron, der verhindert, dass die Abrechnung stockt.

In diesem Artikel8 Abschnitte

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

  1. 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).
  2. 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 actiontime von GLPI).
  3. Erstellen Sie den Vertrag in der Registerkarte Stundenverträge: Name, Einheit (1:1-Beziehung), Gesamtstunden, Abrechnungstag, Periodizität und Warnschwelle.
  4. Konfigurieren Sie die Kriterien in der Registerkarte Bedingungen: die Gruppen und/oder ITIL-Kategorien, über die ein Ticket diesem Vertrag zugeordnet wird.
  5. 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 VertragAngewandte RegelEin Ticket fällt in den Vertrag, wenn
KeineNur die EinheitImmer (es genügt, zur Einheit des Vertrags zu gehören)
Nur GruppenZugehörigkeit innerhalb des TypsEine zugewiesene Gruppe steht auf der Liste des Vertrags
Nur KategorienZugehörigkeit innerhalb des TypsDie ITIL-Kategorie ist in den Regeln des Vertrags enthalten
Gruppen UND KategorienAND zwischen den TypenGruppe 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.

Häufig gestellte Fragen

In Minuten. Für 40 Stunden geben Sie 2400 ein. Es ist der häufigste Konfigurationsfehler: Die Eingabe „40“ legt einen Vertrag über 40 Minuten an, und der Saldo läuft schon beim ersten Ticket über.

Fast immer, weil die automatischen Aktionen von GLPI nicht im externen Modus (CLI) laufen. Die CronTasks billing, cleanup und reconcile werden nicht ausgeführt, der Zyklus wird nicht abgeschlossen, und Änderungen an Aufgaben werden nicht synchronisiert. Prüfen Sie den lastrun in glpi_crontasks und richten Sie den System-Cron auf front/cron.php ein.

Über die Einheit (1:1-Beziehung, Pflicht) in Kombination mit optionalen Kriterien für Gruppe und Kategorie. Sind beide ausgefüllt, gilt UND (AND): Zugewiesene Gruppe und Kategorie müssen übereinstimmen. Ist nur eines konfiguriert, genügt dieses. Ohne Kriterium fällt jedes Ticket der Einheit hinein.

Ja. Der actiontime der Aufgabe ist die maßgebliche Quelle; der Hook onTicketTaskUpdated synchronisiert den billable_time in Echtzeit, und der Cron reconcile korrigiert alle 4 Stunden jede Abweichung. Falls es sich nicht ausgewirkt hat, führen Sie „Verträge neu berechnen“ in der Registerkarte Daten aus.

Nein. Das Modul ist nur für GLPI 11 verfügbar. In GLPI 10 messen Sie Zeit mit dem nativen Dauerfeld oder mit ActualTime, doch die Saldoverwaltung pro Vertrag erfordert die Migration auf GLPI 11.

Ja, seit Version 3.6. Der Schalter „nicht abrechenbar“ pro Aufgabe erfasst die Zeit, bucht sie aber nicht vom Vertragssaldo ab – nützlich für Kulanzeinsätze, die Sie dokumentieren möchten, ohne sie vom Kontingent abzuziehen.

Brauchen Sie Hilfe?