Fahrtenbuch
Fahrten zum Kunden dokumentieren, Kilometerstand per Foto erkennen und optional automatisch abrechnen
- Author: nienhausdavid
- Repository: https://github.com/nienhausdavid/fahrtenbuch
- GitHub stars: 0
- Forks: 0
- License: MIT
- Category: HR & Payroll
- Maintenance: Actively Maintained
- Frappe versions: v16
Install Fahrtenbuch
bench get-app https://github.com/nienhausdavid/fahrtenbuch
Add the Frappe Gems badge to your README
Maintain Fahrtenbuch? Paste this into your README:
[](https://frappegems.com/gems/apps/nienhausdavid/fahrtenbuch)
About Fahrtenbuch
Fahrtenbuch
Frappe-App für ERPNext v15/v16: Fahrten zum Kunden dokumentieren, Kilometerstand per Fotoerkennung erfassen und optional automatisch abrechnen.
Ein Techniker legt pro Fahrt eine Fahrt an: Zeitraum, Start/Ziel, Fotos vom Tacho am Anfang und am Ende. Der Kilometerstand wird dabei per KI-Bilderkennung automatisch vorgeschlagen (siehe "Kilometerstand-Erkennung" unten), lässt sich aber jederzeit von Hand eintragen oder korrigieren. Beim Buchen wird die Fahrzeit immer, die gefahrene Strecke optional als Position in einen Auftrag übernommen.
Kein Finanzamt-taugliches Fahrtenbuch: keine Geschäftlich/Privat-Kennzeichnung, keine lückenlose Erfassung. Ein praktisches Log für Kundenbesuche.
Aufbau
fahrtenbuch/
├── pyproject.toml
├── license.txt
├── README.md
├── README.en.md
└── fahrtenbuch/
├── __init__.py # Versionsnummer
├── hooks.py # doctype_js + doc_events
├── modules.txt # "Fahrtenbuch"
├── patches.txt
├── public/
│ ├── js/fahrtenbuch.js # Feld-Defaults, Site-Visit-Uebernahme, OCR-Trigger
│ ├── js/fahrtenbuch_einstellungen.js # "Modelle abrufen"-Button
│ ├── js/project.js # "Fahrt mit Timer starten"-Button auf dem Projekt-Formular
│ └── images/fahrtenbuch-logo.svg
├── translations/
│ └── en.csv # Englische Uebersetzung (App-Ebene, nicht im Modulordner!)
└── fahrtenbuch/ # Modulordner
├── fahrtenbuch.py # before_submit (Abrechnung) / get_odometer_reading / check_app_permission
├── ocr.py # Kilometerstand per OpenAI-kompatibler Vision-API erkennen
├── project_dashboard.py # ergaenzt "Fahrten" in den Projekt-Verknuepfungen
└── doctype/
├── fahrt/
│ ├── fahrt.json # Haupt-Doctype, submittable
│ └── fahrt.py # Controller (Zeiten/Kilometerstand pruefen, Distanz/Dauer berechnen)
└── fahrtenbuch_einstellungen/
└── fahrtenbuch_einstellungen.json # Single-Doctype: API-URL/Modell/Schluessel
Kein install.py: Es gibt keine Custom Fields auf Kern-Doctypes und keine
sonstigen Datensätze, die manuell aufgeräumt werden müssten — alles gehört
zum Modul "Fahrtenbuch" und wird von uninstall-app dadurch bereits
vollständig entfernt.
Das Formular-Skript ist eine Datei, kein Client-Script-Datensatz. Es verschwindet restlos mit der App und unterliegt nicht dem Client-Script-Cache im Browser.
Sprache
Die App ist auf Deutsch geschrieben (Feldbezeichnungen, Meldungen) und liefert
eine englische Übersetzung mit (fahrtenbuch/translations/en.csv). Das ist
das normale Frappe-Verfahren, nur in umgekehrter Richtung wie bei der
Schwester-App site_visit
(dort Englisch als Quelle, Deutsch als Übersetzung): der deutsche Text im
Code/in der Doctype-JSON bleibt hier die Quelle, die CSV-Datei übersetzt für
Nutzer mit Sprache "Englisch". Frappe wählt die Sprache automatisch passend
zum jeweiligen Nutzer.
Standardbegriffe, die bereits über Frappe/ERPNext selbst übersetzt sind
(z. B. "Customer", "Employee", "Vehicle", "Sales Order", "Item"), sind
bewusst nicht nochmal in en.csv enthalten. Übersetzt sind nur die für
diese App eigenen Begriffe und Texte.
Nach Änderungen an Texten im Code: neue/geänderte Strings auch in en.csv
ergänzen, sonst bleiben sie auf Englisch unübersetzt (Deutsch als Fallback).
Kilometerstand-Erkennung
Die App liest den Kilometerstand aus einem Tacho-Foto über eine beliebige
OpenAI-kompatible API aus (fahrtenbuch/ocr.py, Chat-Completions-Format
mit Bild) — funktioniert damit z. B. mit Ollama (eigener
Server, eigenes Netz, z. B. per NetBird erreichbar,
getestet mit einem Steam Deck als Host), LM Studio, oder echtem OpenAI.
Einrichtung: Doctype "Fahrtenbuch Einstellungen" öffnen (Suche im Awesomebar) und ausfüllen:
- API-URL: Basis-URL ohne
/chat/completionsam Ende, z. B.http://:11434/v1für Ollama oderhttps://api.openai.com/v1 - Modell: z. B.
qwen3.5:9b— Button "Verfügbare Modelle abrufen" fragt die eingetragene API direkt nach den dort tatsächlich vorhandenen Modellen (GET .../models, Teil des OpenAI-Standards) und zeigt sie zur Auswahl an, testet dabei auch eine gerade eingetippte, noch nicht gespeicherte API-URL - API-Schlüssel: nur nötig, falls die API einen verlangt (bei den meisten lokal/selbst gehosteten Servern leer lassen)
- Artikel Fahrzeit: Vorbelegung für das gleichnamige Pflichtfeld auf einer neuen Fahrt — bleibt dort weiterhin pro Fahrt änderbar
Keine Standardwerte hinterlegt — ohne Eintrag bleibt die automatische Erkennung schlicht deaktiviert. Ist die API nicht erreichbar/nicht konfiguriert oder erkennt nichts Eindeutiges, bleibt das Kilometerstand-Feld einfach leer bzw. unverändert — die Fahrt lässt sich immer ganz normal von Hand ausfüllen und buchen, die Erkennung ist reine Komfortfunktion.
Echte Handy-Fotos werden vor dem Versand automatisch auf max. 1024px
Kantenlänge herunterskaliert (ocr.py, MAX_IMAGE_DIMENSION). Ohne das
haben mehrere MB grosse/16-Megapixel-Fotos im Test dazu geführt, dass die
API entweder mit einer leeren Antwort oder gar nicht reagiert hat — mit
verkleinertem Bild lief dieselbe Anfrage zuverlässig und korrekt durch.
ocr.py ist bewusst ein eigenes, kleines Modul: falls das API-Format später
wechseln sollte, muss nur diese eine Funktion angepasst werden.
Timer
"Timer starten"/"Timer stoppen" (im Formular und beim Anlegen aus dem
Projekt heraus) setzen nicht nur start_time/end_time, sondern speichern
sofort — genau wie ERPNexts eigener Timesheet-Timer
(erpnext/public/js/projects/timer.js, ruft nach dem Setzen von from_time
ebenfalls direkt frm.save() auf). Ohne das sofortige Speichern ginge ein
laufender Timer bei einem Reload oder Schliessen der Seite verloren, weil ein
neues, ungespeichertes Dokument nur im Browser existiert.
Damit ein Entwurf mit nur laufendem Timer überhaupt speicherbar ist, sind
Endzeit, beide Kilometerstände, Auftrag und Artikel Fahrzeit nicht mehr auf
Feldebene Pflicht — sie werden erst beim Buchen selbst geprüft
(Fahrt.before_submit in fahrt.py), mit einer klaren Fehlermeldung, falls
etwas fehlt.
Vor der Installation anpassen
In pyproject.toml und fahrtenbuch/hooks.py Name, E-Mail und Beschreibung
eintragen. Willst du die App anders nennen, muss der Name an vier Stellen
konsistent sein: Ordnername, Paketordner, app_name in hooks.py und name
in pyproject.toml.
Installation (eigener Bench)
cd ~/frappe-bench
bench get-app https://github.com//fahrtenbuch.git
bench --site install-app fahrtenbuch
bench build --app fahrtenbuch
bench --site clear-cache
Installation (Frappe Cloud)
Eigene Apps brauchen dort ein Git-Repository und eine eigene Bench-Gruppe (auf den kleinen Shared-Plänen nicht möglich).
- Repository auf GitHub anlegen und den Inhalt dieses Ordners hochladen
- In Frappe Cloud: Bench-Gruppe → Apps → Add App → From GitHub
- Deploy anstoßen, danach die App auf der Site installieren
Deinstallation
bench --site uninstall-app fahrtenbuch --dry-run # nur anzeigen
bench --site uninstall-app fahrtenbuch
Was dabei entfernt wird:
- die Doctype "Fahrt"
- das Modul „Fahrtenbuch" und alles, was daran hängt
- das Formular-Skript, da es reiner Code ist
Was bewusst bestehen bleibt:
- bereits gebuchte Fahrten
- bereits in Aufträge übernommene Positionen (die Auftragspositionen selbst gehören nicht zu dieser App)
Einrichtung
- Für die Abrechnung werden ein Artikel für die Fahrzeit (Pflicht) und optional ein Artikel für Kilometergeld benötigt — beide mit sinnvoll hinterlegtem Preis/Satz.
- Ist auf derselben Site zusätzlich die Schwester-App
site_visitinstalliert, lässt sich eine Fahrt optional mit einem Kundeneinsatz verknüpfen — Kunde, Projekt und Auftrag werden dann automatisch übernommen. Lose Kopplung über die Doctype "Site Visit", keine harte Abhängigkeit. - Im Projekt-Formular gibt es unter "Verknüpfungen" jetzt eine Gruppe
"Fahrten" (additiv über
override_doctype_dashboards, ergänzt die bestehende Liste statt sie zu ersetzen). Die "+"-Verknüpfung dort legt eine neue Fahrt an — überfrm.make_methods(Frappes eigener Erweiterungspunkt fürForm.make_new()) statt der Standard-Vorbelegung, die nur das Projekt-Feld setzen würde. Zusätzlich ein eigenständig sichtbarer Button "Fahrt mit Timer starten" oben im Formular (frm.page.add_button, landet nicht in der "..."-Sammelablage) mit demselben Effekt. - Beide Wege legen die Fahrt standardmäßig mit bereits laufendem Timer an
(Projekt/Kunde vorbelegt, Startzeit = jetzt, sofort gespeichert) und
öffnen direkt danach die Kamera für das Start-Kilometerstand-Foto
(
frappe.ui.Capture— dieselbe Klasse, die auch der Kamera-Knopf im normalen Anhänge-Dialog nutzt; auf dem Handy öffnet das sofort die Kamera-App, am Desktop den Webcam-Stream). Beides einzeln abschaltbar in "Fahrtenbuch Einstellungen" → "Fahrt aus Projekt anlegen": "Timer automatisch starten" und "Kamera automatisch öffnen" (Standard: beide an).
Eigene App im Desk
Die App bringt ein eigenes Logo mit (public/images/fahrtenbuch-logo.svg) und
registriert sich über add_to_apps_screen/app_logo_url in hooks.py als
eigene Kachel auf der Apps-Übersicht (/apps), mit direktem Sprung in die
Fahrt-Liste (keine eigene Workspace-Seite dazwischen).
Berechtigungen
| Rolle | Lesen | Schreiben | Anlegen | Buchen | Stornieren |
|---|---|---|---|---|---|
| System Manager | ✓ | ✓ | ✓ | ✓ | ✓ |
| Projects Manager | ✓ | ✓ | ✓ | ✓ | ✓ |
| Employee | eigene | eigene | ✓ | eigene | – |
| Projects User | ✓ | – | – | – | – |
| Accounts User | ✓ | – | – | – | – |
Es gibt bewusst keine eigene, engere Techniker-Rolle als Fixture (Rollen sind nicht modulgebunden und würden beim Deinstallieren als Karteileiche zurückbleiben); wer den Zugriff über die Standardrolle "Employee" hinaus einschränken will, legt manuell eine eigene Rolle an.
Erweiterungsideen
- "Neuer Auftrag"-Dialog direkt aus der Fahrt heraus (wie in
site_visit), statt nur einen bestehenden Auftrag wählen zu können. - GPS/Adress-basierte automatische km-Berechnung (z. B. Google Maps Distance Matrix) als Alternative/Ergänzung zum Kilometerstand-Foto.
- Mehrere Fahrten pro Tag zusammenfassen statt Einzelbuchung je Fahrt.
Related HR & Payroll apps for Frappe & ERPNext
- Hrms — Open Source HR and Payroll Software
- Huf — Open-source, self-hosted multi-agent AI infrastructure for teams and apps with support for cloud and local models, tool integrations, workflows, and automation across business systems including Slack, ERPNext, Discord & Gmail.
- Bookings — Hotel Management App for Erpnext
- Employee Self Service — This is the backend component for Nesscale ESS - a mobile app that brings ERPNext to your phone. Employees can manage their HR tasks, sales activities, and projects right from their mobile devices.
- Inventory Tools — A collection of features to streamline and enhance inventory management and manufacturing workflows in ERPNext.
- Check Run — Payables utility for ERPNext
- Next Ai — NextAI is an AI-powered app for Frappe and ERPNext, delivering seamless content generation, automation, and productivity enhancements.
- Projectit — Open Source PWA mobile app to track the Employees out in the field. This mobile app is developed on Frappe Framework and it is integrated with the Project functionalities of ERPNext and integrated tightly with Frappe HR.