FriTTo + Excel: Zeitdaten auf Knopfdruck mit Office Scripts exportieren
Warum Excel nach wie vor unverzichtbar ist
Ihr Team erfasst die Arbeitszeit in FriTTo. Die Buchhaltung arbeitet mit Excel. Und Ihre Projektmanager bauen sich ihre Pivot-Tabellen zusammen. Kommt Ihnen das bekannt vor? Egal, wie leistungsfähig Ihre Zeiterfassungsplattform ist — die Daten müssen dort ankommen, wo Ihre Mitarbeiter tatsächlich arbeiten. Und für die meisten Unternehmen ist das nach wie vor Microsoft Excel.
Genau deshalb haben wir FriTTo von Anfang an API-first gebaut. Statt Sie in unser Berichtsformat zu zwingen, geben wir Ihnen die Werkzeuge, um Ihre Daten in jede beliebige Umgebung zu ziehen.
Heute zeigen wir Ihnen, wie Sie FriTTo direkt mit Excel verbinden — per Office Scripts, ohne technische Umwege, manuelle Exporte oder Copy-Paste-Marathons.
Was Sie erhalten
Wir haben eine fertige Excel-Vorlage mit integriertem Office Script vorbereitet, das die FriTTo-API aufruft und Ihre Tabelle automatisch befüllt. Das steckt drin:
- Blatt — Einstellungen — tragen Sie Ihre API-URL, den Zeitraum und Ihren API-Schlüssel ein. Mehr Konfiguration brauchen Sie nicht.
- Blatt — Daten — nach dem Ausführen des Scripts erscheinen hier Ihre Zeiteinträge mit allen Details: Datum, Kunde, Projekt, Beschreibung, erfasste Minuten, Abrechenbarkeit, Genehmigungsstatus, Mitarbeiterinformationen und Kostensätze.
- Office Script (TypeScript) — ein schlankes Script, das Ihre Einstellungen liest, die FriTTo REST API aufruft und die Ergebnisse direkt in Excel schreibt. Automatisch formatierte Überschriften, optimierte Spaltenbreiten und aktivierter Autofilter.
So funktioniert’s: Schritt für Schritt
Schritt 1: Vorlage öffnen
Laden Sie die FriTTo Export Vorlage herunter und öffnen Sie Excel in der Web oder Desktop Version (Microsoft 365 erforderlich für Office Scripts).
Schritt 2: Einstellungen konfigurieren
Füllen Sie auf dem Einstellungen-Blatt vier Felder aus:
- API-Basis-URL — die URL ist bereits vorausgefüllt:
https://api.steinpilz-fritto.de. Hier müssen Sie nichts ändern. - VON Datum — Beginn des Exportzeitraums.
- BIS Datum — Ende des Zeitraums.
- API-Schlüssel — Ihr persönlicher API-Schlüssel aus FriTTo (siehe unten, wie Sie einen erstellen).
Schritt 3: API-Schlüssel in FriTTo erstellen
Melden Sie sich in FriTTo an und klicken Sie oben rechts auf Ihr Profilsymbol. Scrollen Sie nach unten zum Bereich Persönliche API Tokens und klicken Sie auf API Token hinzufügen. Vergeben Sie einen Namen (z.B. „excel“), legen Sie ein Ablaufdatum fest und kopieren Sie den generierten Schlüssel. Fügen Sie ihn auf dem Einstellungen-Blatt in das Feld API-Schlüssel ein — fertig.
Wichtig: Der Datenexport steht nur Benutzern mit einer der folgenden Rollen zur Verfügung: Administrator, Department Manager, Manager oder Reviewer. Ob Sie die nötige Berechtigung haben, erkennen Sie daran, dass im Menü der Punkt Berichte → Alle Zeitberichte sichtbar ist.
Schritt 4: Script hinzufügen
Gehen Sie zum Reiter Automatisieren im Excel-Menüband, klicken Sie auf Neues Skript und wählen Sie Im Code-Editor erstellen aus. Ersetzen Sie den angezeigten Code vollständig mit dem folgenden Script:
/**
* Fritto Export — Office Script (TypeScript) — Deutsche Version
*
* Liest Einstellungen vom Blatt "Einstellungen", ruft die TimeTracker-API auf
* und füllt das Blatt "Daten" mit den exportierten Zeiteinträgen.
*
* Verwendung:
* 1. Öffnen Sie die Excel-Datei in Excel für das Web oder Excel Desktop (Microsoft 365)
* 2. Gehen Sie zum Reiter "Automatisieren"
* 3. Klicken Sie auf "Neues Skript", fügen Sie diesen Code ein und speichern Sie
* 4. Füllen Sie das Blatt "Einstellungen" aus und klicken Sie im Skript-Editor auf "Ausführen"
*/
async function main(workbook: ExcelScript.Workbook): Promise<void> {
const settingsSheet = workbook.getWorksheet("Einstellungen");
if (!settingsSheet) {
throw new Error("Blatt 'Einstellungen' nicht gefunden.");
}
// Eingaben lesen
const apiUrl = toString(settingsSheet.getRange("B1").getValue()).trim();
const fromDate = formatDateValue(settingsSheet.getRange("B2").getValue());
const toDate = formatDateValue(settingsSheet.getRange("B3").getValue());
const apiKey = toString(settingsSheet.getRange("B4").getValue()).trim();
// Validierung
if (!apiUrl) throw new Error("API-Basis-URL ist erforderlich.");
if (!fromDate) throw new Error("VON Datum ist erforderlich.");
if (!toDate) throw new Error("BIS Datum ist erforderlich.");
if (fromDate > toDate) throw new Error("VON Datum muss vor oder gleich dem BIS Datum liegen.");
if (!apiKey) throw new Error("API-Schlüssel fehlt.");
// Anfrage-URL erstellen
const baseUrl = apiUrl.replace(/\/+$/, "");
const requestUrl = `${baseUrl}/api/app/export-to-excel?From=${fromDate}&To=${toDate}`;
// Daten von API abrufen
console.log(`Daten werden abgerufen von: ${requestUrl}`);
const response = await fetch(requestUrl, {
method: "GET",
headers: {
"X-Api-Key": apiKey,
"Accept": "application/json",
},
});
if (!response.ok) {
const body = await response.text();
switch (response.status) {
case 400:
throw new Error(`Ungültige Anfrage (HTTP 400). Details: ${body.substring(0, 300)}`);
case 401:
throw new Error("Authentifizierung fehlgeschlagen. Bitte überprüfen Sie Ihren API-Schlüssel.");
case 403:
throw new Error("Zugriff verweigert. Ihr API-Schlüssel hat keine Berechtigung für diese Daten.");
case 404:
throw new Error("API-Endpunkt nicht gefunden. Bitte überprüfen Sie die API-Basis-URL.");
default:
throw new Error(`Serverfehler (HTTP ${response.status}). Bitte versuchen Sie es später erneut.`);
}
}
const result: { items: ExportEntry[] } = await response.json();
const items = result.items;
// Daten-Blatt befüllen
const dataSheet = workbook.getWorksheet("Daten");
if (!dataSheet) {
throw new Error("Blatt 'Daten' nicht gefunden.");
}
// Vorhandene Daten löschen
const usedRange = dataSheet.getUsedRange();
if (usedRange) {
usedRange.clear();
}
// Vorhandenen Auto-Filter entfernen
const existingFilter = dataSheet.getAutoFilter();
if (existingFilter.getIsDataFiltered()) {
existingFilter.remove();
}
if (items.length === 0) {
console.log("Keine Daten für den angegebenen Zeitraum gefunden.");
return;
}
// Spaltenüberschriften
const headers = [
"Datum", "Kunde", "Projekt", "Beschreibung", "Aufgaben-URL",
"Erfasste Minuten", "Abrechenbar?", "Genehmigt?",
"Vorname", "Nachname", "Mitarbeitergruppen", "Kostensatz", "Währung",
];
// Überschriften schreiben
const headerRange = dataSheet.getRangeByIndexes(0, 0, 1, headers.length);
headerRange.setValues([headers]);
headerRange.getFormat().getFont().setBold(true);
headerRange.getFormat().getFill().setColor("#4472C4");
headerRange.getFormat().getFont().setColor("#FFFFFF");
headerRange.getFormat().setRowHeight(30);
// Datenzeilen erstellen
const rows: (string | number)[][] = items.map((item) => [
item.date ?? "",
item.client ?? "",
item.project ?? "",
item.description ?? "",
item.taskUrl ?? "",
item.trackedMinutes ?? 0,
item.isBillable ? "Ja" : "Nein",
item.isApproved ? "Ja" : "Nein",
item.firstName ?? "",
item.lastName ?? "",
item.employeeGroups ?? "",
item.costRate ?? "",
item.currency ?? "",
]);
// Daten schreiben
const dataRange = dataSheet.getRangeByIndexes(1, 0, rows.length, headers.length);
dataRange.setValues(rows);
// Spaltenbreite automatisch anpassen
dataSheet.getUsedRange()?.getFormat().autofitColumns();
// Auto-Filter anwenden
dataSheet.getAutoFilter().apply(dataSheet.getUsedRange());
console.log(`${items.length} Einträge erfolgreich exportiert.`);
}
/** Excel-Zellwert (String, Zahl oder Datumsseriennummer) in yyyy-mm-dd String umwandeln. */
function formatDateValue(value: string | number | boolean): string {
if (value === null || value === undefined || value === "") return "";
if (typeof value === "number") {
// Excel-Datumsseriennummer -> yyyy-mm-dd
const date = new Date(Math.round((value - 25569) * 86400 * 1000));
const y = date.getUTCFullYear();
const m = String(date.getUTCMonth() + 1).padStart(2, "0");
const d = String(date.getUTCDate()).padStart(2, "0");
return `${y}-${m}-${d}`;
}
return value.toString().trim();
}
/** Zellwert sicher in String umwandeln. */
function toString(value: string | number | boolean): string {
if (value === null || value === undefined) return "";
return value.toString();
}
interface ExportEntry {
date: string;
client: string;
project: string;
description: string;
taskUrl: string;
trackedMinutes: number;
isBillable: boolean;
isApproved: boolean;
userId: string;
firstName: string;
lastName: string;
employeeGroups: string;
costRate: number | null;
currency: string | null;
}
Tipp: Nach dem Speichern klicken Sie auf die drei Punkte und wählen Sie + In Arbeitsmappe hinzufügen aus, um einen praktischen Ausführen-Button direkt in Ihre Tabelle einzufügen.
Schritt 5: Ausführen
Klicken Sie auf Ausführen — entweder im Office Script-Editor auf dem Button Ausführen oder über den grünen Button Ausführen auf dem Datenblatt, das Sie im vorherigen Schritt hinzugefügt haben. Das Script ruft Ihre Zeiteinträge über die FriTTo-API ab und füllt das Daten-Blatt. Überschriften werden formatiert, Spalten automatisch angepasst und Filter aktiviert. Ihre Daten sind nun bereit zur Analyse.
Was Sie mit den Daten machen können
Sobald Ihre Zeiteinträge in Excel sind, stehen Ihnen alle Möglichkeiten offen:
- Pivot-Tabellen — abrechenbare Stunden nach Kunde, Projekt oder Teammitglied in Sekunden aufschlüsseln.
- Kostenanalyse — erfasste Minuten mit Kostensätzen kombinieren und die Projektrentabilität berechnen.
- Kundenabrechnung — nach Kunde und Zeitraum filtern und in Ihren Billing-Workflow exportieren.
- Genehmigungsverfolgung — auf einen Blick sehen, welche Einträge genehmigt sind und welche noch ausstehen.
- Geplante Aktualisierung — das Office Script mit Power Automate kombinieren und den Export automatisch ausführen — täglich, wöchentlich oder monatlich.
Warum das wichtig ist
Die meisten Zeittracker bieten bestenfalls einen CSV-Export — einen einmaligen, manuellen Prozess, der nicht mehr funktioniert, sobald sich Ihre Daten ändern. Mit der FriTTo-API und Office Scripts erhalten Sie eine direkte Verbindung zwischen Ihren Zeiterfassungsdaten und Ihrer Tabelle. Zeitraum anpassen, Ausführen klicken — und Sie haben in Sekunden aktuelle Daten.
Das ist API-first in der Praxis: Ihre Daten, Ihr Format, Ihr Workflow — ohne Kompromisse.