Coodle
Compliance & Rendicontazione

Moodle e Fondimpresa: automatizzare la rendicontazione

Come generare i tracciati Fondimpresa e Forma.Temp direttamente da Moodle senza export manuali in Excel. Plugin custom vs Reportbuilder: quando usare l'uno o l'altro.

CoodlePubblicato il 8 maggio 20268 min min di lettura
TL;DR

Se gestisci un piano Fondimpresa con Moodle e finisci sempre a esportare in Excel e sistemare colonne a mano, non è un problema tuo: è che Moodle non parla il linguaggio dei fondi interprofessionali nativamente. In questo articolo vediamo cosa chiedono i fondi, dove Moodle si ferma, e come automatizzare la rendicontazione con Reportbuilder o un plugin custom.

Se lavori in un ente accreditato o in una direzione formazione aziendale che eroga piani su Fondimpresa, Forma.Temp o Fondirigenti, conosci il momento: fine del piano formativo, 2.000 ore erogate, 180 partecipanti — e la rendicontazione da consegnare entro giovedì.

Moodle tiene tutto: completamenti, ore connesse, valutazioni. Ma il tracciato XML che Fondimpresa richiede non lo genera nessuno.

Ci siamo passati. Questo articolo spiega cosa serve e come strutturare la soluzione.

Cosa chiedono Fondimpresa e i fondi interprofessionali

Ogni fondo interprofessionale italiano ha le proprie specifiche tecniche per la rendicontazione delle attività formative. Il tracciato standard di Fondimpresa (versione corrente sul portale ufficiale) richiede, per ogni partecipante e per ogni modulo formativo:

  • Codice fiscale partecipante
  • Ore di partecipazione effettiva (non ore erogate: le ore realmente frequentate)
  • Codice modulo formativo
  • Data di completamento
  • Eventuale risultato della valutazione finale (se il piano lo prevede)

Forma.Temp ha una struttura analoga ma usa un formato CSV con separatori e codifiche particolari. Fondirigenti richiede un XML con namespace specifici.

Il problema comune: questi dati esistono in Moodle, ma sono distribuiti su tabelle diverse — mdl_user, mdl_course, mdl_course_completions, mdl_logstore_standard_log — e nessuna vista predefinita li aggrega nel formato richiesto.

Perché l'export manuale fallisce sopra i 1.000 utenti

Sotto i 200 partecipanti, un export CSV + Excel può essere gestibile, a patto di avere una persona dedicata che sa cosa sta facendo. Sopra quella soglia, iniziano i problemi:

Errori di mappatura. Le colonne CSV di Moodle non corrispondono one-to-one ai campi del tracciato. Ogni export richiede un'operazione di trasformazione manuale che introduce errori.

Ore errate. Moodle traccia il tempo di connessione alla sessione, non il tempo di apprendimento effettivo. Un partecipante che tiene la finestra aperta 3 ore ma non interagisce appare come "3 ore frequentate". I fondi interprofessionali non accettano questo.

Nessuna validazione. Se un codice fiscale è sbagliato nel profilo Moodle, lo scopri quando il fondo rigetta il tracciato — non prima.

Nessuna traccia di chi ha fatto cosa. In caso di audit, ricostruire l'iter di generazione del tracciato da un file Excel è impossibile.

Reportbuilder vs plugin custom: quando basta il primo

Il modulo Reportbuilder introdotto in Moodle 4.1 è significativamente più potente dei vecchi report custom. Permette di costruire query su 30+ entità del database Moodle con join multipli, filtri, aggregazioni e export in CSV/Excel/PDF.

Per la rendicontazione ai fondi, Reportbuilder può essere sufficiente se:

  • Il tuo fondo accetta un CSV con campi standard (nome, cognome, CF, ore, completamento)
  • Sei disposto a fare un passaggio manuale di validazione prima dell'invio
  • Il volume di partecipanti è inferiore ai 500 per piano

La limitazione principale di Reportbuilder per questo use case: non produce XML strutturato, non valida i codici fiscali contro un pattern, non carica automaticamente il file sul portale del fondo.

Un plugin custom è necessario quando:

  • Il fondo richiede un XML con struttura specifica (namespace, XSD validation)
  • Vuoi la validazione automatica dei CF prima dell'export
  • Hai più fondi con formati diversi e non vuoi gestirne la differenza a mano
  • Vuoi automatizzare l'invio (upload FTP/SFTP al portale del fondo)
  • Devi tenere un log di ogni rendicontazione generata per audit

Esempio: query per estrarre completamenti con ore effettive

Questo è il tipo di query che costruiamo come base per la rendicontazione. La logica centrale: unire i completamenti corsi (mdl_course_completions) con il tempo effettivo dal logstore (mdl_logstore_standard_log), aggregando per utente e per corso.

SELECT
    u.id          AS user_id,
    u.lastname    AS cognome,
    u.firstname   AS nome,
    u.idnumber    AS codice_fiscale,
    c.shortname   AS codice_corso,
    cc.timecompleted AS data_completamento,
    ROUND(
        SUM(CASE WHEN l.action = 'viewed' THEN 1 ELSE 0 END) / 60.0,
        2
    ) AS ore_effettive
FROM
    mdl_course_completions cc
    JOIN mdl_user u ON u.id = cc.userid
    JOIN mdl_course c ON c.id = cc.course
    LEFT JOIN mdl_logstore_standard_log l
        ON l.userid = cc.userid
        AND l.courseid = cc.course
        AND l.timecreated BETWEEN cc.timestarted AND cc.timecompleted
WHERE
    cc.timecompleted IS NOT NULL
    AND cc.course IN (/* lista ID corsi del piano */)
GROUP BY
    u.id, u.lastname, u.firstname, u.idnumber,
    c.shortname, cc.timecompleted
ORDER BY
    u.lastname, u.firstname;

Il risultato di questa query è la base per costruire il tracciato. Le ore "effettive" qui sono una stima basata sugli eventi viewed — un punto di partenza, non una misura precisa. Per una misura più accurata serve tracciare eventi heartbeat personalizzati, ma questa complessità dipende dal fondo e dal tipo di rendicontazione richiesta.

Come strutturiamo un plugin local per la rendicontazione

Per le integrazioni più complete, sviluppiamo un local plugin Moodle — il tipo di plugin pensato esattamente per questo: funzionalità aziendali che non appartengono al core e non devono essere nei plugin di terze parti.

La struttura minima:

// local/fondimpresa_export/version.php
<?php
defined('MOODLE_INTERNAL') || die();
 
$plugin->version   = 2026050800;
$plugin->requires  = 2023042400; // Moodle 4.2+
$plugin->component = 'local_fondimpresa_export';
$plugin->maturity  = MATURITY_STABLE;
$plugin->release   = '1.0.0';

Il file lib.php contiene la logica principale: query dei dati, validazione, generazione del tracciato e (opzionalmente) upload automatico.

// local/fondimpresa_export/lib.php
<?php
defined('MOODLE_INTERNAL') || die();
 
function local_fondimpresa_export_generate_tracciato(
    array $course_ids,
    string $fondo = 'fondimpresa'
): string {
    global $DB;
 
    // 1. Recupero completamenti con ore
    $records = $DB->get_records_sql("
        SELECT u.idnumber AS cf, u.lastname, u.firstname,
               c.shortname, cc.timecompleted,
               COALESCE(ore.minuti, 0) / 60.0 AS ore_effettive
        FROM {course_completions} cc
        JOIN {user} u ON u.id = cc.userid
        JOIN {course} c ON c.id = cc.course
        LEFT JOIN (
            SELECT userid, courseid, COUNT(*) AS minuti
            FROM {logstore_standard_log}
            WHERE action = 'viewed'
            GROUP BY userid, courseid
        ) ore ON ore.userid = cc.userid AND ore.courseid = cc.course
        WHERE cc.timecompleted IS NOT NULL
        AND cc.course " . $DB->get_in_or_equal($course_ids),
        $course_ids
    );
 
    // 2. Validazione CF
    foreach ($records as $r) {
        if (!preg_match('/^[A-Z]{6}[0-9]{2}[A-Z][0-9]{2}[A-Z][0-9]{3}[A-Z]$/i', $r->cf)) {
            // Log errore e skip — non blocca l'intero export
            debugging("CF non valido per utente {$r->lastname}: {$r->cf}", DEBUG_DEVELOPER);
        }
    }
 
    // 3. Generazione output (qui CSV — per XML estendi con XMLWriter)
    $adapter = local_fondimpresa_export_get_adapter($fondo);
    return $adapter->render($records);
}

La funzione local_fondimpresa_export_get_adapter() istanzia l'adapter corretto per il fondo (pattern Strategy), così aggiungere Forma.Temp richiede solo un nuovo file adapter_formatemp.php senza toccare la logica centrale.

Validazione prima dell'invio: i controlli che salvano

I tracciati rigettati dai fondi hanno quasi sempre le stesse cause:

  1. Codice fiscale con caratteri errati (spazi, minuscole, caratteri accentati)
  2. Ore dichiarate superiori alla durata del corso (Moodle non valida questo)
  3. Data completamento fuori dal periodo del piano (completamenti registrati dopo la scadenza)
  4. Partecipanti senza profilazione completa (campo idnumber vuoto)

Un plugin ben fatto esegue questi controlli prima di generare il file e produce un report di anomalie — così il responsabile formazione corregge i dati in Moodle prima dell'invio, non dopo il rigetto.

Integrazione con il sistema di reportistica esistente

Una nota operativa: se la tua organizzazione usa già un gestionale HR (Zucchetti, TeamSystem, SAP) che alimenta Moodle via CSV o API, il flusso ideale è:

  1. Il gestionale HR sincronizza utenti su Moodle con CF corretto
  2. Moodle traccia le attività formative
  3. Il plugin genera il tracciato dal dato Moodle arricchito

Questo elimina la doppia gestione dell'anagrafica. Lo abbiamo implementato per organizzazioni da 50 a 150.000 utenti — la logica è la stessa, cambia la scala.

Per approfondire le possibilità di sviluppo custom su Moodle, leggi il nostro articolo su plugin Moodle vs sviluppo custom — dove spieghiamo quando vale la pena sviluppare qualcosa di specifico e come valutare il TCO.

Conclusione: tre punti da portare via

  1. L'export manuale non scala. Sopra i 500 partecipanti per piano, il costo del lavoro manuale supera rapidamente il costo di un plugin custom.

  2. Reportbuilder è un punto di partenza, non la soluzione finale. Ottimo per report interni; limitato per rendicontazione ai fondi che richiede XML strutturato o upload automatico.

  3. La qualità del dato in Moodle è il vero collo di bottiglia. Anche il miglior plugin non può generare un tracciato corretto se i codici fiscali nel database sono sbagliati. Prima di automatizzare la rendicontazione, vale la pena fare un audit dei profili utente.

Hai un piano formativo da rendicontare e Moodle non genera i tracciati che ti servono? Scrivici una riga: in 24 ore ti diciamo se è risolvibile e in quanto tempo.

Domande frequenti

Hai un piano formativo da rendicontare e Moodle non genera i tracciati che ti servono?

Raccontaci la situazione — ti rispondiamo entro 24 ore lavorative.