std.kassensichv — KassenSichV / TSE-Anbindung

Zurück zur Unit-Übersicht

Rechtskonforme Kassensicherungsverordnung-Bibliothek für die gesetzlich vorgeschriebene TSE-Anbindung (Technische Sicherheitseinrichtung). Grundlage: KassenSichV (Kassensicherungsverordnung), BSI TR-03153 und DSFinV-K 2.3.

Die Bibliothek nimmt Kassenbonrohdaten (BelegDaten) entgegen, kommuniziert mit der TSE und liefert alle Pflichtangaben für den Bondruck (SigErgebnis) — einschließlich des QR-Code-Strings nach BSI TR-03153 Anhang A.

Rechtliche Pflichtangaben auf dem Kassenbon:

  • TSE-Seriennummer
  • Fortlaufender Signaturzähler
  • Start- und Endzeitpunkt laut TSE (UTC)
  • ECDSA/SHA-256-Signaturwert (Base64)
  • QR-Code-String (Format V0;{SerNr};{Start};{End};{Zähler};{AnzTrans};{Sig})

Units

Unit Beschreibung
kassensichv.types BelegDaten, SigErgebnis, Prozesstyp-Konstanten (PROZESSTYP_KASSENBELEG, …)
kassensichv.manager TseManager: Einstiegspunkt — TseProcessBeleg, TseOpenBeleg, TseCloseBeleg, Export
kassensichv.mock TseMockNew: Vollständiger Mock-Provider ohne TSE-Hardware für Tests und CI/CD
kassensichv.rest TseRestNew: Cloud-TSE via HTTPS/REST (Fiskaly, Deutsche Fiskal); Bearer-Auth, Retry
kassensichv.file TseFileNew: USB-TSE via Dateisystem (Swissbit, Epson); Poll-basiertes Request/Response
kassensichv.exceptions Strukturierte Fehler-Hierarchie: TseError mit Code + Provider-Info

Provider-Konzept

Das zentrale Designprinzip ist die Dependency Inversion: Die gesamte Kassensoftware nutzt ausschließlich den TseManager. Welche TSE physisch angebunden ist (Cloud, USB, Mock), wird einmalig bei der Initialisierung festgelegt — der übrige Code ist identisch.

Kassensoftware
      │
      │  TseProcessBeleg(mgr, beleg)
      ▼
 TseManager
      │  StartTransaction()
      ├──────────────────────────────► TSE-Provider
      │                                     │
      │                           (Cloud REST / USB / Mock)
      │  FinishTransaction()                │ ECDSA-Signatur
      │◄────────────────────────────────────┘
      │
      │  QR-Code generieren (BSI TR-03153)
      │
      ▼
SigErgebnis → Kassenbon drucken

Wechsel des Providers erfordert nur eine Änderung beim TseManager-Create — der Beleg-Code bleibt unverändert.

Schnellstart

import kassensichv.types;
import kassensichv.mock;
import kassensichv.manager;

fn DruckKassenbon(): void {
    // 1. Provider wählen (hier: Mock für Tests)
    var mgr: int64 := TseMockNew();

    // 2. Beleg befüllen
    var beleg: BelegDaten;
    beleg.prozessTyp  := PROZESSTYP_KASSENBELEG;
    beleg.kassenNr    := "KASSE-001"c;
    beleg.prozessDaten := "Kaffee;2.50_0.00_0.00_0.00_0.00"c;
    beleg.umsatz      := 2500;   // Eurocent

    // 3. Beleg signieren lassen (Start + Finish + QR-Code in einem Schritt)
    var sig: int64 := TseProcessBeleg(mgr, addr beleg);

    // 4. Pflichtangaben drucken
    var s: SigErgebnis := (sig as *SigErgebnis)^;
    Print("TSE-Seriennummer: "c); PrintLn(s.tseSerial as pchar);
    Print("Signaturzähler: "c);   PrintLn(IntToStr(s.sigZaehler)c);
    Print("QR-Code: "c);          PrintLn(s.qrCode as pchar);

    SigErgebnisFree(sig);
    TseManagerFree(mgr);
}

Für echte TSEs nur den Provider tauschen:

// Cloud-TSE (Fiskaly)
var cfg: int64 := '{"api_url":"https://kassensichv.io/api/v1","api_key":"...","client_id":"KASSE-001"}'c;
var mgr: int64 := TseRestNew(cfg);

// USB-TSE (Swissbit-Stick unter /mnt/tse)
var cfg: int64 := '{"base_path":"/mnt/tse","timeout_ms":5000}'c;
var mgr: int64 := TseFileNew(cfg);

Typen-Übersicht

Typ Felder (wichtigste) Zweck
BelegDaten prozessTyp, prozessDaten, kassenNr, umsatz Eingabe: Rohdaten des Kassenbons
SigErgebnis tseSerial, sigZaehler, sigWert, qrCode, success Ausgabe: Pflichtangaben für Bondruck

Alle String-Felder (pchar) in SigErgebnis sind allokiert — Aufrufer muss SigErgebnisFree() aufrufen.

Feld Typ Bedeutung
qrCode int64 (pchar) Vorformatierter QR-Code-String nach BSI TR-03153 Anhang A
sigZaehler int64 Fortlaufender TSE-Vorgangszähler (Pflichtfeld auf Bon)
sigWert int64 (pchar) ECDSA/SHA-256, Base64-kodiert
success int64 1 = signiert, 0 = Fehler → errorMsg auswerten

Mehrstufige Vorgänge

Für Tischbewirtung, Bestellungen mit Zwischenständen oder Zeiterfassung gibt es den dreistufigen Workflow:

import kassensichv.manager;

fn TischBestellung(mgr: int64): void {
    var beleg: BelegDaten;
    beleg.prozessTyp  := PROZESSTYP_KASSENBELEG;
    beleg.kassenNr    := "KASSE-001"c;

    // Transaktion öffnen (TSE vergibt Zähler + Zeitstempel)
    var transId: int64 := TseOpenBeleg(mgr, addr beleg);

    // Zwischenstand nach Vorspeise
    beleg.prozessDaten := "Vorspeise;12.00_0.00_0.00_0.00_0.00"c;
    beleg.umsatz       := 1200;
    TseUpdateBeleg(mgr, transId, addr beleg);

    // Abschluss nach Hauptgang
    beleg.prozessDaten := "Vorspeise+Hauptgang;32.00_0.00_0.00_0.00_0.00"c;
    beleg.umsatz       := 3200;
    var sig: int64 := TseCloseBeleg(mgr, transId, addr beleg);

    var s: SigErgebnis := (sig as *SigErgebnis)^;
    PrintLn(s.qrCode as pchar);

    SigErgebnisFree(sig);
    free(transId);
}

DSFinV-K-Export

Finanzämter können jederzeit den Export des TSE-Audit-Logs anfordern. Die Bibliothek erzeugt eine TAR-Datei (TSE-intern signiert, darf nicht verändert werden) und eine index.json mit Metadaten:

// Export nach /tmp/tse_export/ (Verzeichnis muss existieren)
var ok: int64 := TseExportAuditData(mgr, "/tmp/tse_export"c, "KASSE-001"c);
// Erzeugt: /tmp/tse_export/tse_export.tar  + index.json

index.json enthält: DSFinV-K-Version (2.3), TSE-Seriennummer, Kassen-ID, Export-Zeitpunkt (ISO 8601 UTC).

QR-Code-Format

Der QR-Code-String nach BSI TR-03153 Anhang A hat exakt folgendes Format:

V0;{TSE-Seriennummer};{StartUTC};{EndUTC};{Signaturzähler};{AnzahlTransaktionen};{SignaturBase64}

Beispiel:

V0;MOCK-TSE-0000000000000001;2026-06-12T09:30:00Z;2026-06-12T09:30:01Z;1;1;abc123XYZ...==

Fehlerbehandlung

Alle Fehler der Bibliothek werden als TseError-Struktur mit Code und Provider-Info zurückgegeben. Offene Transaktionen nach einem TseCloseBeleg-Fehler sind ein Compliance-Problem und müssen sofort behandelt werden.

Fehlercode Bedeutung Beispiel
400 Konfigurationsfehler api_key fehlt in ConfigJSON
403 Exportpfad nicht schreibbar Verzeichnis nicht beschreibbar
408 Timeout TSE antwortet nicht innerhalb timeout_ms
409 Transaktionsfehler Offene Transaktion, doppelte TransId
500 Signierfehler ECDSA-Schlüssel ungültig
503 Verbindungsfehler USB-TSE nicht verbunden, Cloud nicht erreichbar

→ Details: kassensichv.exceptions

Prozesstypen (BSI TR-03153)

Konstante Wert Verwendung
PROZESSTYP_KASSENBELEG „Kassenbeleg-V1“ Normaler Kassenbon (Verkauf)
PROZESSTYP_STORNO „Kassenbeleg-V1-Storno“ Stornierter Vorgang
PROZESSTYP_TRAINING „Training“ Trainings-/Testvorgang (kein Steuerbezug)

Detailseiten

Seite Inhalt
kassensichv.types Alle Typen und Konstanten mit Feldbeschreibungen
kassensichv.manager Vollständige Manager-API (alle 7 Funktionen)
kassensichv.mock Mock-Provider — Fehlersimulation, Testzugriff
kassensichv.rest Cloud-TSE REST-Provider — Konfiguration, Retry-Logik
kassensichv.file USB-TSE-Provider — Dateiprotokoll, Poll-Mechanismus
kassensichv.exceptions Fehler-Hierarchie und Behandlungsstrategien

Letzte Aktualisierung: 2026-06-12