Files
Laurent Chedanne dadb1d4f23 OVea version
2026-06-26 10:39:30 +02:00

7.2 KiB

csv-to-timemanager.py — Spécifications d'importation

Objectif

Le script csv-to-timemanager.py lit des fichiers CSV configurés dans config.json et envoie des requêtes vers l'API Nextcloud TimeManager pour créer ou mettre à jour :

  • clients,
  • projets,
  • tâches,
  • entrées de temps.

Il utilise aussi une base MySQL locale pour vérifier l'existence des objets et éviter les doublons.

Sources des données

Le script traite les entrées de chaque CSV listé sous config['calendars']. Chaque entrée doit contenir au minimum :

  • csv_name : chemin du fichier CSV à importer,
  • user_name : login Nextcloud utilisé pour authentifier les requêtes,
  • api_password : mot de passe ou mot de passe d'application Nextcloud.

Il est important de générer la clé API en s'étant connecté avec l'identifiant et non l'email car le script user_name utilise le champ "user_name" pour faire des vérifications en bases de données avant d'ajouter des données.

Colonnes CSV utilisées

Pour chaque ligne du CSV, le script utilise précisément ces colonnes :

  • Description → nom du client TimeManager
  • Categories → nom du projet TimeManager
  • Titre → nom de la tâche TimeManager
  • Date debut → date de début de l'entrée de temps
  • Heure debut → heure de début de l'entrée de temps
  • Date fin → date de fin de l'entrée de temps
  • Heure fin → heure de fin de l'entrée de temps

Correspondance vers TimeManager

Colonne CSV Entité TimeManager Champ TimeManager / usage
Description client name du client
Categories project name du projet
Titre task name de la tâche
Date debut time entry start (date + heure)
Heure debut time entry start (date + heure)
Date fin time entry end (date + heure)
Heure fin time entry end (date + heure)

Traitements appliqués

  1. Lecture du CSV

    • Le fichier est lu avec csv.reader(..., delimiter=';').
    • La première ligne est traitée comme en-tête et sert à associer chaque colonne à une clé de dictionnaire.
  2. Nettoyage des chaînes de texte

    • sanitize(chain) :
      • retire tous les caractères sauf lettres, chiffres et espaces,
      • applique unidecode pour normaliser les accents,
      • strip() pour enlever les espaces en début/fin,
      • capitalize() pour mettre la première lettre en majuscule.
    • sanitize_date(chain) :
      • conserve aussi les caractères - et : supplémentaires (utile pour les dates/heures),
      • applique les mêmes normalisations que sanitize.
  3. Création / existence d'objets

    • Chaque entité est créée indépendamment si elle n'existe pas :
      • Si le client Description n'existe pas, il est créé via create_client().
      • Si le projet Categories n'existe pas (pour ce client), il est créé via create_project().
      • Si la tâche Titre n'existe pas (pour ce projet), elle est créée via create_task().
    • Les actions de création appellent l'API updateObjects avec un payload minimal contenant l'entité concernée.
  4. Insertion d'une entrée de temps

    • Le script construit start et end en concaténant Date debut + Heure debut et Date fin + Heure fin.
    • Il envoie ensuite un objet times.created à l'API updateObjects.

Validation et gestion des doublons

  • Avant d'ajouter une entrée de temps, le script vérifie si une entrée identique existe déjà dans la base :
    • il cherche d'abord une entrée avec les mêmes user_id, start (date+heure début) et end (date+heure fin).
    • si une telle entrée existe, il valide que le task, le project et le client correspondent.
    • si tous les critères correspondent, l'import est ignoré pour éviter un doublon.
  • Important : deux entrées avec les mêmes client/projet/tâche mais à des heures différentes créent 2 entrées TimeManager distinctes (elles ne sont pas considérées comme des doublons).

Gestion des données manquantes

  • Si user_name ou api_password manque dans la configuration pour un calendrier, ce calendrier est ignoré.
  • Dans le CSV, si client_name (Description) et project_name (Categories) sont tous deux vides, la ligne est ignorée.
  • Si le client existe mais que son UUID ne peut pas être récupéré après création, le traitement de la ligne est abandonné avec un message d'erreur.
  • Limitations actuelles (risque) : Le script ne valide pas que Titre, Date debut, Heure debut, Date fin ou Heure fin sont présents :
    • Si Titre est vide, une tâche avec un nom vide peut être créée ou recherchée.
    • Si Date debut, Heure debut, Date fin ou Heure fin sont vides, une entrée de temps avec start ou end incomplet sera créée.
    • Ce comportement est indésirable et devrait être amélioré (voir docs/todo.md).

Cas particuliers

  • Pour l'existence d'un client/projet/tâche, la comparaison se fait avec les noms nettoyés (sanitize) et uniquement les objets dont status != "deleted".
  • create_client() retourne maintenant l'UUID extrait de la réponse API si disponible. Si la réponse ne contient pas d'UUID, le script effectue une seconde récupération via la base de données.
  • create_project() et create_task() ne retournent pas d'UUID : ils comptent sur les recherches suivantes (get_project_uuid_by_name, get_task_uuid_by_name) pour retrouver l'objet créé.

Notes d'implémentation

  • Les requêtes vers TimeManager utilisent toujours POST /api/updateObjects.
  • Les objets envoyés contiennent des champs vides (uuid, commit, created, changed) pour laisser le serveur les remplir si nécessaire.
  • Le script n'envoie pas de données de deleted ou updated : il se contente de créer des objets dans created.

Résumé rapide

Le script transforme chaque ligne CSV en un client/projet/tâche puis une entrée de temps, en appliquant un nettoyage de texte simple et en évitant le double-import des mêmes périodes.

Champs obligatoires pour créer une entrée de temps

Pour qu'une ligne CSV soit importée avec succès en tant qu'entrée de temps TimeManager, les champs suivants doivent être renseignés :

  • Description : non vide (nom du client) OU Categories : non vide (nom du projet) — au moins un des deux.
  • Categories : non vide (nom du projet).
  • Titre : non vide (nom de la tâche).
  • Date debut : non vide et valide.
  • Heure debut : non vide et valide.
  • Date fin : non vide et valide.
  • Heure fin : non vide et valide.

Note actuellement : le script ne valide pas strictement ces conditions. Il est recommandé d'améliorer ce point (voir docs/todo.md).

Le point clef est que seules les colonnes suivantes sont exploitées : Description, Categories, Titre, Date debut, Heure debut, Date fin, Heure fin.