Inhaltsverzeichnis

kassensichv.manager

Zurück zur KassenSichV-Übersicht

Haupteinstiegspunkt für Kassensoftware-Entwickler. Der TseManager orchestriert den vollständigen TSE-Transaktionsablauf: Transaktion öffnen → TSE signieren lassen → QR-Code generieren.

Wichtig: Der TseManager ist nicht thread-sicher. Pro physische Kasse genau eine Instanz verwenden.

Import

import kassensichv.types;
import kassensichv.manager;

Erzeugen / Freigeben

Der Manager wird immer mit einem konkreten Provider erstellt. Welcher Provider verwendet wird, bestimmt sich aus der verwendeten TseXxxNew-Funktion (aus kassensichv.mock, kassensichv.rest oder kassensichv.file).

// (Import des jeweiligen Providers nötig — z.B. kassensichv.mock)
pub fn TseManagerFree(mgr: int64): void;

Der Manager übernimmt den Besitz des Providers. TseManagerFree gibt beides frei.

Einfacher Kassenbon (ProcessBeleg)

pub fn TseProcessBeleg(mgr: int64, beleg: int64): int64;
// Gibt *SigErgebnis zurück (allokiert) — caller muss SigErgebnisFree aufrufen
// Wirft bei Fehler: errorMsg in SigErgebnis und success=0

Ablauf intern:

  1. StartTransaction → TSE öffnet Transaktion, vergibt Zähler
  2. FinishTransaction → TSE signiert mit ECDSA-Schlüssel
  3. QR-Code-String nach BSI TR-03153 Anhang A generieren

Bei Fehler in FinishTransaction ist die TSE-Transaktion offen — das ist ein Compliance-Problem. Der Manager liefert success=0 und errorMsg zurück; die Kassensoftware muss diese Situation behandeln (manuell abschließen oder stornieren).

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

fn main(): int64 {
    var mgr: int64 := TseMockNew();

    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       := 250;

    var sig: int64 := TseProcessBeleg(mgr, addr beleg);
    if sig == 0 then {
        PrintLn("Signierung fehlgeschlagen"c);
        TseManagerFree(mgr);
        return 1;
    }

    var s: SigErgebnis := (sig as *SigErgebnis)^;
    if s.success == 0 then {
        Print("Fehler: "c); PrintLn(s.errorMsg as pchar);
    } else {
        PrintLn(s.qrCode as pchar);
    }

    SigErgebnisFree(sig);
    TseManagerFree(mgr);
    return 0;
}

Mehrstufige Vorgänge

Für Tischbewirtung, Bestellungen mit Zwischenständen oder Split-Zahlungen:

TseOpenBeleg

pub fn TseOpenBeleg(mgr: int64, beleg: int64): int64;
// Gibt pchar TransId zurück (allokiert) — nach TseCloseBeleg mit free() freigeben
// Befüllt beleg.transId und beleg.startZeit

TseUpdateBeleg

pub fn TseUpdateBeleg(mgr: int64, transId: int64, beleg: int64): int64;
// Gibt *SigErgebnis zurück (Zwischenstand, ohne QR-Code) — SigErgebnisFree aufrufen
// Optional — kann mehrfach zwischen Open und Close aufgerufen werden

TseCloseBeleg

pub fn TseCloseBeleg(mgr: int64, transId: int64, beleg: int64): int64;
// Gibt *SigErgebnis zurück (allokiert, mit QrCode befüllt) — SigErgebnisFree aufrufen
// Wirft bei Fehler: success=0 — offene Transaktion bei TSE → Compliance-Problem!

Vollständiges Beispiel — Tischbestellung:

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

    // Transaktion öffnen
    var transId: int64 := TseOpenBeleg(mgr, addr beleg);

    // Vorspeise geliefert
    beleg.prozessDaten := "Vorspeise;8.00_0.00_0.00_0.00_0.00"c;
    beleg.umsatz       := 800;
    var zwi: int64 := TseUpdateBeleg(mgr, transId, addr beleg);
    SigErgebnisFree(zwi);

    // Hauptgang geliefert + Kassenbon abschließen
    beleg.prozessDaten := "Vorspeise+Hauptgang;28.00_0.00_0.00_0.00_0.00"c;
    beleg.umsatz       := 2800;
    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

pub fn TseExportAuditData(mgr: int64, targetPath: int64, kassenNr: int64): int64;
// 1 = Export erfolgreich, 0 = Fehler (Pfad nicht schreibbar, Provider-Fehler)
// Erzeugt: {targetPath}/tse_export.tar  (TSE-interne Daten, signiert)
//          {targetPath}/index.json       (DSFinV-K-Metadaten)

Das TAR-Archiv stammt direkt von der TSE und ist intern signiert. Es darf nicht verändert werden — Finanzamt-Prüfsoftware (IDEA) validiert die TSE-Signatur über die Dateiintegrität.

index.json enthält:

{
  "dsfinvk_version": "2.3",
  "tse_serial": "...",
  "kasse_id": "KASSE-001",
  "export_timestamp": "2026-06-12T09:00:00Z"
}

var ok: int64 := TseExportAuditData(mgr, "/var/kassensichv/export"c, "KASSE-001"c);
if ok == 0 then {
    PrintLn("Export fehlgeschlagen — Verzeichnis nicht schreibbar?"c);
}

Status und Seriennummer

pub fn TseGetStatus(mgr: int64): int64;
// Gibt pchar JSON-Status-String zurück (allokiert) — mit free() freigeben
// Felder: provider, serial, status, ggf. provider-spezifische Details

pub fn TseGetSerial(mgr: int64): int64;
// Gibt pchar TSE-Seriennummer zurück (allokiert) — mit free() freigeben

var status: int64 := TseGetStatus(mgr);
PrintLn(status as pchar);
// Beispiel: {"provider":"RestTseProvider","serial":"XYZ123","status":"connected"}
free(status);

var serial: int64 := TseGetSerial(mgr);
Print("TSE: "c); PrintLn(serial as pchar);
free(serial);

Funktions-Übersicht

Funktion Parameter Rückgabe Beschreibung
TseManagerFree mgr Manager + Provider freigeben
TseProcessBeleg mgr, beleg *SigErgebnis Einzel-Transaktion (Start+Finish+QR)
TseOpenBeleg mgr, beleg pchar TransId Transaktion öffnen
TseUpdateBeleg mgr, transId, beleg *SigErgebnis Transaktion aktualisieren
TseCloseBeleg mgr, transId, beleg *SigErgebnis Transaktion abschließen
TseExportAuditData mgr, path, kassenNr int64 (1/0) DSFinV-K-Export
TseGetStatus mgr pchar JSON TSE-Status abfragen
TseGetSerial mgr pchar TSE-Seriennummer

Letzte Aktualisierung: 2026-06-12