====== kassensichv.manager ======
→ [[lyx_-_programmiersprache:units:kassensichv|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:
- ''StartTransaction'' → TSE öffnet Transaktion, vergibt Zähler
- ''FinishTransaction'' → TSE signiert mit ECDSA-Schlüssel
- 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