→ 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 kassensichv.types;
import kassensichv.manager;
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.
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:
StartTransaction → TSE öffnet Transaktion, vergibt ZählerFinishTransaction → TSE signiert mit ECDSA-Schlüssel
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;
}
Für Tischbewirtung, Bestellungen mit Zwischenständen oder Split-Zahlungen:
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
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
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);
}
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);
}
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);
| 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