mite-Daten in Watson importieren
Ich migriere derzeit meine Zeiterfassung für Hobbyprojekte vom kostenpflichtigen Web-Tool mite auf das Open-Source-Command-Line Projekt Watson. Mite hat einen größeren Funktionsumfang mit dem Management von Kunden und Stundensätzen, allerdings benötige ich diese Funktionen derzeit nicht. Den Kommentar zu jeder Buchung in mite nutze ich auch nahezu kaum.
Deshalb zeige ich an dieser Stelle, wie man seine Daten von mite in Watson integrieren kann.
Vorarbeit
Als erstes muss man sich die bestehenden Daten von mite exportieren. Das geht
ganz leicht über die Funktion Account -> Backup
in mite. Hier kann man sich
einen XML-Export der eigenen Daten herunterladen.
Aus diesen Daten habe ich mir zunächst die Projekte und Kunden auflisten lassen. Kundeneinträge werden von Watson nicht unterstützt, man könnte sich allerdings ein entsprechendes Tag zu jedem Kunden anlegen oder jeden Kunden als ein Projekt verwalten. In meinem Fall ist der Eintrag relativ irrelevant, weil ich hier eher Themen verwalte als echte Kunden (z.B. Fernuni Hagen).
Die Projekte sind hingegen sehr wichtig, allerdings will ich diese teilweise nicht als Projekt in Watson importieren, sondern als Tag zu einem neuen Sammelprojekt. Deshalb habe ich mir für jedes Projekt aus mite ein Mapping auf einen neuen Projektnamen mit ggfs. Tags angelegt.
Die bestehenden Projekte kann man aus dem mite-Export anzeigen mit:
xmllint --xpath '/backup/projects/project/name/text()' mite-backup.xml.gz
Daraus habe ich mir folgendermaßen ein Mapping für den Import in Watson aufgebaut:
mapping = {
'Studium / Vorlesung-X': ('university', ['vorlesung-x']),
'Molescrape': ('molescrape', ['platform']),
# ...
}
Hierbei steht der erste Eintrag im Tupel für das Projekt, das ich in Watson anlegen möchte, und der zweite Eintrag steht für die Liste an Tags, die ich dafür vergeben möchte.
Konvertierung
Damit können wir mit einem kleinen Python-Skript die Einträge aus dem mite-Export auslesen und per Command-Line-Befehl in Watson eintragen. Theoretisch könnte man auch die Watson-Log-Datei direkt ändern, allerdings ist deren Format nicht dokumentiert und ihr Format ist damit als instabiler anzusehen als die öffentliche Command-Line-API. Außerdem müsste man sich dann die ID für jeden Eintrag selbst berechnen und es ist nicht dokumentiert, ob dies ein zufälliger Wert ist oder ein Hash aus den Daten.
from lxml import etree
from datetime import datetime, timedelta
import subprocess
mapping = {
'Studium / Vorlesung-X': ('university', ['vorlesung-x']),
'Molescrape': ('molescrape', ['platform']),
}
tree = etree.parse('mite-backup.xml.gz')
# create a lookup table of all project ids to project names
projects = {}
for project in tree.xpath('/backup/projects/project'):
id_ = int(project.xpath('./id/text()')[0])
name = project.xpath('./name/text()')[0]
projects[id_] = name
# loop through all time entries and add them to watson with a command
# line call
for time_entry in tree.xpath('/backup/time-entries/time-entry'):
try:
project_id = int(time_entry.xpath('./project-id/text()')[0])
except IndexError:
# some entries have no project assigned, ignore them
print('skipped one entry')
continue
project_name = projects[project_id]
date = time_entry.xpath('./date-at/text()')[0]
duration = int(time_entry.xpath('./minutes/text()')[0])
# mite does not have exact dates when something was done, thus we just
# use 8 am as the start time
startdate = datetime.strptime(date, '%Y-%m-%d') + timedelta(hours=8)
enddate = startdate + timedelta(minutes=duration)
watson_project = mapping[project_name][0]
watson_tags = ['+{}'.format(tag) for tag in mapping[project_name][1]]
command = [
'watson',
'add',
'--from',
datetime.strftime(startdate, '%Y-%m-%d %H:%M:%S'),
'--to',
datetime.strftime(enddate, '%Y-%m-%d %H:%M:%S'),
watson_project
] + watson_tags
subprocess.run(command)