Vendre des forfaits d'heures sans un solde fiable, c'est piloter à l'aveugle : le client conteste la facture, le technicien ne sait pas combien il reste et la clôture du mois vire à l'archéologie de tableur. Le module Contract Hours de NexTool résout cela directement dans GLPI, en chronométrant le temps sur la timeline du ticket et en le débitant du bon contrat. Ce guide montre comment le configurer, quels champs prêtent le plus à confusion et l'erreur d'exploitation qui bloque toute la facturation.
Ce que GLPI natif n'offre pas
Le champ Durée de la tâche (stocké en secondes dans la colonne actiontime) enregistre du temps, mais ne connaît ni contrat, ni quota, ni solde. Vous saisissez les minutes à la main, sans chronomètre, sans arrondi facturable et sans répondre à la seule question que le client pose chaque mois : « combien ai-je consommé et combien reste-t-il ? ». Contract Hours ajoute cette couche par-dessus le champ natif, sans le remplacer.
Comment le temps est capturé
Le technicien contrôle un chronomètre directement sur la timeline du ticket :
- Start lance le décompte ; un badge flottant reste visible sur toutes les pages de GLPI tant qu'une mesure est active.
- Pause / Resume décomptent les pauses (réunion, déjeuner) sans perdre le temps accumulé.
- Stop arrondit le temps, crée une TicketTask privée et débite le contrat lié.
À la résolution ou à la clôture du ticket, un hook arrête le chronomètre automatiquement (auto-stop). C'est le détail qui évite qu'un chronomètre oublié tourne toute la nuit et gonfle la consommation.
Pas à pas : configurer un contrat
- Installez et activez le module dans NexTool -> Modules -> Contract Hours. L'installation crée les tables, la VIEW de synthèse et enregistre trois CronTasks (billing, cleanup, reconcile).
- Définissez le minimum facturable dans les Paramètres (par défaut 15 min). L'arrondi se fait en deux temps : d'abord au multiple du minimum, puis à un multiple de 5 (compatibilité avec l'
actiontimede GLPI). - Créez le contrat dans l'onglet Contrats d'Heures : nom, entité (relation 1:1), Total d'heures, jour de facturation, périodicité et seuil d'alerte.
- Configurez les critères dans l'onglet Conditions : les groupes et/ou catégories ITIL qui font qu'un ticket « tombe » dans ce contrat.
- Ajustez la visibilité dans l'onglet Visibilité : utilisateurs, profils et groupes qui voient le contrat sur le tableau de bord client. Une liste vide signifie visible pour tous ceux qui ont le droit de lecture.
L'erreur courante ici : le champ « Total d'heures » est stocké en MINUTES. Saisir « 40 » en pensant à 40 heures crée en réalité un contrat de 40 minutes, et le solde explose dès le premier ticket. Pour 40 heures, indiquez 2400.
La règle de résolution est ET, pas OU
Décider quand un ticket appartient à un contrat est l'endroit où l'on voit le plus de mauvaises configurations. La logique combine l'entité (toujours obligatoire, 1:1) avec des critères optionnels de groupe et de catégorie :
| Critères sur le contrat | Règle appliquée | Le ticket rejoint le contrat quand |
|---|---|---|
| Aucun | Entité seule | Toujours (il suffit d'appartenir à l'entité du contrat) |
| Groupes seuls | Appartenance dans le type | Un groupe attribué figure dans la liste du contrat |
| Catégories seules | Appartenance dans le type | La catégorie ITIL figure dans les règles du contrat |
| Groupes ET catégories | AND entre les types | Groupe dans la liste ET catégorie dans les règles (les deux) |
Autrement dit : avec groupe ET catégorie renseignés, le ticket ne rejoint le contrat que si les deux correspondent. Configurer les deux en attendant un comportement « OU », c'est ce qui envoie la moitié des tickets dans la carte « Sans Contrat ».
actiontime est la source de vérité
Depuis la version 3.4.2, le module traite l'actiontime de la TicketTask comme source primaire. Le billable_time du chronomètre est maintenu synchronisé par trois couches : le hook onTicketTaskUpdated (temps réel, quand vous éditez la tâche via GLPI natif), le cron reconcile (toutes les 4h) et le bouton « Recalculer les Contrats ». En pratique, éditer la durée de la tâche directement dans GLPI se répercute sur le solde du contrat - à condition que le cron tourne.
Le cron doit être en mode externe
Voici l'erreur d'exploitation qui bloque tout. Contract Hours dépend de trois CronTasks : billing (clôture le cycle et remet à zéro la consommation), cleanup (ferme les chronomètres orphelins) et reconcile (synchronise et re-résout). Elles ne s'exécutent que si les actions automatiques de GLPI sont en mode externe (CLI). En mode GLPI (déclenché par l'accès web), un environnement à faible trafic peut passer des jours sans clôturer le cycle de facturation, tandis que les chronomètres oubliés accumulent des heures fantômes.
Assurez le cron système pointant vers l'exécuteur d'actions automatiques de GLPI :
# /etc/cron.d/glpi - declenche les actions automatiques de GLPI chaque minute (mode externe)
# Adaptez le chemin a votre installation (sous GLPI 11 le document root est public/)
* * * * * www-data /usr/bin/php /var/www/glpi/front/cron.php >/dev/null 2>&1
Confirmez ensuite que les tâches du module sont planifiées, en mode externe et avec une exécution récente :
-- Etat des 3 CronTasks de Contract Hours
SELECT name, frequency, mode, state, lastrun
FROM glpi_crontasks
WHERE itemtype = 'PluginNextoolContracthoursCron';
-- mode=2 (externe/CLI), state=1 (planifiee) et un lastrun recent = sain.
Diagnostiquer un solde divergent
Dans la maintenance des environnements clients, le schéma se répète : le contrat est bien créé, les premiers tickets débitent correctement et, trois semaines plus tard, le solde « se fige ». Dans presque tous les cas, la cause est la même : les actions automatiques étaient en mode web, pas en CLI externe. Sans le cron externe, billing ne clôture jamais le cycle, reconcile ne synchronise jamais les modifications faites sur la tâche et cleanup ne supprime jamais les chronomètres orphelins de celui qui a oublié le Stop le vendredi. C'est pourquoi la première requête que nous lançons dans un diagnostic Contract Hours porte sur glpi_crontasks, pas sur le solde : si le lastrun des trois tâches n'est pas récent, le problème n'est pas le module, c'est l'infrastructure GLPI.
Le cron confirmé, le second suspect est le billable_time désynchronisé de l'actiontime après une édition rétroactive. Mesurez l'écart avant de recalculer à l'aveugle :
-- Chronometres dont le temps facture a devie de l'actiontime de la tache (source de verite)
SELECT t.id, t.tickets_id,
t.billable_time/60 AS min_facture,
tt.actiontime/60 AS min_tache,
(t.billable_time - tt.actiontime) AS diff_secondes
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;
En cas d'écarts, le bouton « Recalculer les Contrats » (onglet Données) exécute la synchronisation et recalcule la consommation. Pour vérifier le solde, en rappelant que les champs sont en minutes :
-- Solde par contrat actif (valeurs en minutes, converties en heures)
SELECT name, entities_id,
total_hours/60 AS quota_h,
used_hours/60 AS consomme_h,
(total_hours - used_hours)/60 AS solde_h
FROM glpi_plugin_nextool_contracthours_contracts
WHERE is_active = 1
ORDER BY solde_h;
Audit, alertes et courtoisie
Chaque édition rétroactive de temps est enregistrée - qui a édité, quand et quelle était la valeur précédente - dans l'onglet Journaux. C'est la traçabilité dont vous êtes reconnaissant quand un client conteste une heure imputée. Les alertes se déclenchent par pourcentage de consommation (seuil par défaut 80 %) et par deux conditions de contrat : expiré (date de fin dans le passé) et heures dépassées. Chaque condition peut être réglée sur « ne rien faire », « alerte » (popup jaune que l'on peut fermer) ou « blocage ». Une règle fine s'applique : le blocage rouge n'agit qu'à la création de ticket par le centre d'assistance (Service Catalog) ; un ticket déjà ouvert n'est jamais bloqué, il reçoit seulement l'alerte. Depuis la version 3.6 il existe aussi le bouton « non facturable » (courtoisie) : le temps est comptabilisé mais ne débite pas le solde - pratique pour une intervention que vous voulez enregistrer sans entamer le quota du client.
Transformer des heures de ticket en facturation défendable - avec un solde, un relevé et un tableau de bord que le client comprend - est exactement ce que résout le module Contract Hours du plugin NexTool. Si vous maintenez GLPI et clôturez encore le mois dans un tableur, parlez-nous.
Ce contenu a été produit avec l'aide de l'intelligence artificielle et révisé par l'équipe Nextool Solutions.