Controllo delle ore per contratto in GLPI con Contract Hours

Guida tecnica per configurare Contract Hours in GLPI: cronometro sulla timeline, contratti per entità con risoluzione gruppo E categoria, arrotondamento fatturabile, saldo in minuti e il cron esterno che evita il blocco della fatturazione.

Vendere pacchetti di ore senza un saldo affidabile significa operare al buio: il cliente contesta la fattura, il tecnico non sa quanto resta e la chiusura del mese diventa archeologia da foglio di calcolo. Il modulo Contract Hours di NexTool risolve tutto dentro GLPI, cronometrando il tempo sulla timeline del ticket e addebitandolo al contratto giusto. Questa guida mostra come configurarlo, quali campi generano più confusione e l'errore operativo che blocca l'intera fatturazione.

Cosa non offre GLPI nativo

Il campo Durata dell'attività (memorizzato in secondi nella colonna actiontime) registra il tempo, ma non conosce contratto, quota né saldo. Digiti i minuti a mano, senza cronometro, senza arrotondamento fatturabile e senza rispondere all'unica domanda che il cliente pone ogni mese: "quanto ho usato e quanto resta?". Contract Hours aggiunge questo strato sopra il campo nativo, senza sostituirlo.

Come viene catturato il tempo

Il tecnico controlla un cronometro direttamente sulla timeline del ticket:

  • Start avvia il conteggio; un badge fluttuante resta visibile su tutte le pagine di GLPI finché è attiva una misurazione.
  • Pause / Resume scontano le pause (riunione, pranzo) senza perdere il tempo accumulato.
  • Stop arrotonda il tempo, crea una TicketTask privata e addebita il contratto collegato.

Alla risoluzione o chiusura del ticket, un hook ferma il cronometro automaticamente (auto-stop). È il dettaglio che evita che un cronometro dimenticato giri tutta la notte gonfiando il consumo.

Passo dopo passo: configurare un contratto

  1. Installa e attiva il modulo in NexTool -> Moduli -> Contract Hours. L'installazione crea le tabelle, la VIEW di riepilogo e registra tre CronTasks (billing, cleanup, reconcile).
  2. Definisci il minimo fatturabile nelle Impostazioni (predefinito 15 min). L'arrotondamento avviene in due passi: prima al multiplo del minimo, poi a un multiplo di 5 (compatibilità con l'actiontime di GLPI).
  3. Crea il contratto nella scheda Contratti di Ore: nome, entità (relazione 1:1), Totale ore, giorno di fatturazione, periodicità e soglia di allerta.
  4. Configura i criteri nella scheda Condizioni: i gruppi e/o le categorie ITIL che fanno "ricadere" un ticket in quel contratto.
  5. Regola la visibilità nella scheda Visibilità: utenti, profili e gruppi che vedono il contratto nella dashboard del cliente. Un elenco vuoto significa visibile a tutti con permesso di lettura.

L'errore comune qui: il campo "Totale ore" è memorizzato in MINUTI. Chi digita "40" pensando a 40 ore crea in realtà un contratto di 40 minuti e vede il saldo esplodere già al primo ticket. Per 40 ore, indica 2400.

La regola di risoluzione è E, non O

Decidere quando un ticket appartiene a un contratto è dove vediamo più configurazioni sbagliate. La logica combina l'entità (sempre obbligatoria, 1:1) con criteri opzionali di gruppo e categoria:

Criteri sul contrattoRegola applicataIl ticket entra nel contratto quando
NessunoSolo l'entitàSempre (basta appartenere all'entità del contratto)
Solo gruppiAppartenenza nel tipoUn gruppo assegnato è nell'elenco del contratto
Solo categorieAppartenenza nel tipoLa categoria ITIL è nelle regole del contratto
Gruppi E categorieAND tra i tipiGruppo nell'elenco E categoria nelle regole (entrambi)

In altre parole: con gruppo E categoria impostati, il ticket entra nel contratto solo se entrambi corrispondono. Configurare i due aspettandosi un comportamento "O" è ciò che spinge metà dei ticket nella scheda "Senza Contratto".

actiontime è la fonte di verità

Dalla versione 3.4.2 il modulo tratta l'actiontime della TicketTask come fonte primaria. Il billable_time del cronometro è mantenuto sincronizzato da tre livelli: l'hook onTicketTaskUpdated (in tempo reale, quando modifichi l'attività dal GLPI nativo), il cron reconcile (ogni 4h) e il pulsante "Ricalcola Contratti". In pratica, modificare la durata dell'attività direttamente in GLPI si riflette sul saldo del contratto - a patto che il cron sia in esecuzione.

Il cron deve essere in modalità esterna

Ecco l'errore operativo che blocca tutto. Contract Hours dipende da tre CronTasks: billing (chiude il ciclo e azzera il consumo), cleanup (chiude i cronometri orfani) e reconcile (sincronizza e ri-risolve). Girano solo se le azioni automatiche di GLPI sono in modalità esterna (CLI). In modalità GLPI (avviata dall'accesso web), un ambiente a basso traffico può passare giorni senza chiudere il ciclo di fatturazione, mentre i cronometri dimenticati accumulano ore fantasma.

Assicura il cron di sistema che punta all'esecutore delle azioni automatiche di GLPI:

# /etc/cron.d/glpi - avvia le azioni automatiche di GLPI ogni minuto (modalita esterna)
# Adatta il percorso alla tua installazione (in GLPI 11 il document root e public/)
* * * * * www-data /usr/bin/php /var/www/glpi/front/cron.php >/dev/null 2>&1

Poi conferma che le attività del modulo siano pianificate, in modalità esterna e con esecuzione recente:

-- Stato delle 3 CronTasks di Contract Hours
SELECT name, frequency, mode, state, lastrun
FROM glpi_crontasks
WHERE itemtype = 'PluginNextoolContracthoursCron';
-- mode=2 (esterna/CLI), state=1 (pianificata) e lastrun recente = sano.

Diagnosi di un saldo divergente

Nella manutenzione degli ambienti dei clienti, lo schema si ripete: il contratto viene creato bene, i primi ticket addebitano correttamente e, tre settimane dopo, il saldo "si blocca". In quasi tutti i casi la causa è la stessa: le azioni automatiche erano in modalità web, non in CLI esterna. Senza il cron esterno, billing non chiude mai il ciclo, reconcile non sincronizza mai le modifiche fatte sull'attività e cleanup non elimina mai i cronometri orfani di chi ha dimenticato lo Stop il venerdì. Per questo la prima query che eseguiamo in una diagnosi di Contract Hours è quella su glpi_crontasks, non quella sul saldo: se il lastrun delle tre attività non è recente, il problema non è il modulo, è l'infrastruttura di GLPI.

Confermato il cron, il secondo sospetto è il billable_time desincronizzato dall'actiontime dopo una modifica retroattiva. Misura lo scarto prima di ricalcolare alla cieca:

-- Cronometri il cui tempo fatturato si e discostato dall'actiontime dell'attivita (fonte di verita)
SELECT t.id, t.tickets_id,
       t.billable_time/60 AS min_fatturato,
       tt.actiontime/60   AS min_task,
       (t.billable_time - tt.actiontime) AS diff_secondi
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;

In presenza di scarti, il pulsante "Ricalcola Contratti" (scheda Dati) esegue la sincronizzazione e ricalcola il consumo. Per verificare il saldo, ricordando che i campi sono in minuti:

-- Saldo per contratto attivo (valori in minuti, convertiti in ore)
SELECT name, entities_id,
       total_hours/60 AS quota_h,
       used_hours/60  AS consumato_h,
       (total_hours - used_hours)/60 AS saldo_h
FROM glpi_plugin_nextool_contracthours_contracts
WHERE is_active = 1
ORDER BY saldo_h;

Audit, allerte e cortesia

Ogni modifica retroattiva del tempo è registrata - chi l'ha modificata, quando e qual era il valore precedente - nella scheda Log. È la tracciabilità che apprezzi quando un cliente contesta un'ora imputata. Le allerte scattano per percentuale di consumo (soglia predefinita 80%) e per due condizioni del contratto: scaduto (data di fine nel passato) e ore superate. Ogni condizione può essere impostata su "non fare nulla", "allerta" (popup giallo chiudibile) o "blocco". Vale una regola sottile: il blocco rosso agisce solo alla creazione del ticket da parte dell'help desk (Service Catalog); un ticket già aperto non viene mai bloccato, riceve solo l'allerta. Dalla versione 3.6 esiste anche l'interruttore "non fatturabile" (cortesia): il tempo viene contabilizzato ma non addebita il saldo - utile per l'intervento che vuoi registrare senza intaccare la quota del cliente.

Trasformare le ore di ticket in fatturazione difendibile - con saldo, estratto conto e una dashboard che il cliente capisce - è esattamente ciò che risolve il modulo Contract Hours del plugin NexTool. Se gestisci GLPI e chiudi ancora il mese su un foglio di calcolo, parla con noi.


Questo contenuto è stato prodotto con l'ausilio dell'intelligenza artificiale e revisionato dal team Nextool Solutions.

Domande Frequenti

In minuti. Per 40 ore, indica 2400. È l'errore di configurazione più comune: digitare "40" crea un contratto di 40 minuti e il saldo esplode già al primo ticket.

Quasi sempre perché le azioni automatiche di GLPI non sono in modalità esterna (CLI). Le CronTasks billing, cleanup e reconcile non girano, il ciclo non si chiude e le modifiche alle attività non si sincronizzano. Verifica lastrun in glpi_crontasks e configura il cron di sistema che punta a front/cron.php.

Per entità (relazione 1:1 obbligatoria) combinata con criteri opzionali di gruppo e categoria. Con entrambi impostati la logica è E (AND): il gruppo assegnato e la categoria devono corrispondere entrambi. Se ne è configurato solo uno, basta quello. Senza criteri, qualsiasi ticket dell'entità entra.

Sì. L'actiontime dell'attività è la fonte di verità; l'hook onTicketTaskUpdated sincronizza billable_time in tempo reale e il cron reconcile corregge ogni scarto ogni 4h. Se non si è riflesso, esegui "Ricalcola Contratti" nella scheda Dati.

No. Il modulo è solo per GLPI 11. Su GLPI 10 misuri il tempo con il campo nativo di durata o con ActualTime, ma il controllo del saldo per contratto richiede la migrazione a GLPI 11.

Sì, dalla versione 3.6. L'interruttore "non fatturabile" per attività contabilizza il tempo ma non addebita il saldo del contratto - utile per interventi di cortesia che vuoi registrare senza intaccare la quota.

Hai bisogno di aiuto?