====== std.edi.messages ====== Infrastruktur-Nachrichten für den EDIFACT-Austausch: Empfangsquittungen, Fehlermeldungen und Freitext. Diese Nachrichten sind kein Geschäftsinhalt, sondern die technische Kommunikationsebene zwischen zwei EDI-Partnern. * **CONTRL** — Syntax-Quittung (positiv oder negativ). Jeder empfangene Interchange wird quittiert. * **APERAK** — Anwendungsebenen-Fehlermeldung. Wird nach erfolgreicher Syntax-Prüfung gesendet, wenn eine Nachricht inhaltlich abgelehnt wird. * **GENRAL** — Freitext-Nachricht für alles, was kein eigenes Message-Format hat. import std.edi.messages; import std.alloc; import std.string; fn Feld(p: int64, l: int64): pchar { var b: int64 := alloc(l + 1); var i: int64 := 0; while (i < l) { poke8(b + i, peek8(p + i)); i := i + 1; } poke8(b + l, 0); return b as pchar; } fn main(): int64 { var out: int64 := alloc(2048); // 1. Positive Syntaxquittung auf den Interchange IC000042 var n: int64 := EdiContrlOk("IC000042"c, "4098765000004"c, "4012345000009"c, out, 2048); PrintLn(Feld(out, n)); var res: int64 := alloc(EDI_CONTRL_SIZE); EdiContrlRead(out, n, res); PrintLn(StrConcat("Status: ", IntToStr(peek64(res + EDI_CONTRL_STATUS)))); // 2. Ablehnung: Pflichtsegment fehlt, Segmentposition 12 n := EdiContrlErr("IC000042"c, 12, EDI_ERR_MISSING_SEG, out, 2048); PrintLn(Feld(out, n)); EdiContrlRead(out, n, res); PrintLn(StrConcat(StrConcat("Status: ", IntToStr(peek64(res + EDI_CONTRL_STATUS))), StrConcat(" Fehlercode: ", IntToStr(peek64(res + EDI_CONTRL_ERRCODE))))); // 3. Fachliche Ablehnung (APERAK) n := EdiAperakWrite("BST-2026-0815"c, 14, "Artikel 04012345678918 unbekannt"c, out, 2048); PrintLn(Feld(out, n)); var ap: int64 := alloc(EDI_APERAK_SIZE); EdiAperakRead(out, n, ap); PrintLn(StrConcat("APERAK-Text: ", Feld(peek64(ap + EDI_APERAK_TEXT), peek64(ap + EDI_APERAK_TEXTLEN)))); return 0; } UNB+UNOA:1+4098765000004+4012345000009+000000:0000+IC000042'UNH+1+CONTRL:1:901:UN'UCI+IC000042+4012345000009+4098765000004+7'UNT+3+1'UNZ+1+IC000042' Status: 7 UNB+UNOA:1+++000000:0000+IC000042'UNH+1+CONTRL:1:901:UN'UCI+IC000042+++4+25+12'UNT+3+1'UNZ+1+IC000042' Status: 4 Fehlercode: 25 BGM+313++9'RFF+ACE:BST-2026-0815'ERC+14'FTX+AAO++Artikel 04012345678918 unbekannt' APERAK-Text: Artikel 04012345678918 unbekannt > **CONTRL bringt seinen Umschlag selbst mit.** ''EdiContrlOk'' und ''EdiContrlErr'' schreiben einen vollständigen Interchange von UNB bis UNZ — anders als die Fachnachrichten (ORDERS, INVOIC …), die nur den Rumpf liefern und den Umschlag aus ''std.edi.core'' brauchen. Das Datum bleibt dabei auf ''000000:0000''; wer ein echtes Datum braucht, baut die Quittung von Hand mit ''EdiUnbWrite''. > > ''EdiContrlErr'' trägt **keine** Partner-IDs ein (die Felder bleiben leer) — für den Versand an einen konkreten Partner den Umschlag selbst erzeugen. ---- ===== Imports ===== * ''std.edi.core'' * ''std.alloc'' ---- ===== Structs ===== ==== EdiContrl (EDI_CONTRL_SIZE = 40 Bytes) ==== ^ Offset-Konstante ^ Inhalt ^ | ''EDI_CONTRL_STATUS'' | Status: ''7''=akzeptiert, ''4''=abgelehnt (Gruppen-Ebene), ''5''=abgelehnt (Nachrichten-Ebene) | | ''EDI_CONTRL_ERRCODE'' | UN/EDIFACT-Fehlercode (0 = kein Fehler) | | ''EDI_CONTRL_SEGPOS'' | Position des fehlerhaften Segments (0 = Interchange-Ebene) | | ''EDI_CONTRL_ICREF / EDI_CONTRL_ICREFLEN'' | Zeiger auf die ICR des quittierten Interchange | Status-Konstanten: ^ Konstante ^ Wert ^ Bedeutung ^ | ''EDI_CONTRL_ACCEPTED'' | 7 | Interchange vollständig akzeptiert | | ''EDI_CONTRL_REJECTED4'' | 4 | Funktionale Gruppe abgelehnt | | ''EDI_CONTRL_REJECTED5'' | 5 | Nachricht abgelehnt | Standard-Fehlercodes (UN/EDIFACT S005): ^ Konstante ^ Wert ^ Bedeutung ^ | ''EDI_ERR_SYNTAX_VER'' | 2 | Syntax-Version nicht unterstützt | | ''EDI_ERR_TEST_FLAG'' | 7 | Testflag-Mismatch | | ''EDI_ERR_INVALID_VALUE'' | 14 | Ungültiger Wert | | ''EDI_ERR_MISSING_SEG'' | 25 | Pflicht-Segment fehlt | ==== EdiAperak (EDI_APERAK_SIZE = 40 Bytes) ==== ^ Offset-Konstante ^ Inhalt ^ | ''EDI_APERAK_ERRCODE'' | Anwendungs-Fehlercode | | ''EDI_APERAK_REFMSG / EDI_APERAK_REFLEN'' | Zeiger auf referenzierte Nachrichten-ID | | ''EDI_APERAK_TEXT / EDI_APERAK_TEXTLEN'' | Zeiger auf Fehlertext | ==== EdiGenral (EDI_GENRAL_SIZE = 48 Bytes) ==== ^ Offset-Konstante ^ Inhalt ^ | ''EDI_GENRAL_SUBJECT / EDI_GENRAL_SUBJLEN'' | Betreff (aus BGM/C002) | | ''EDI_GENRAL_BODY / EDI_GENRAL_BODYLEN'' | Textkörper — **alloziert**, Caller muss freigeben | | ''EDI_GENRAL_REFMSG / EDI_GENRAL_REFLEN'' | Referenz auf die zugrundeliegende Nachricht | **Achtung GENRAL-Body**: ''EdiGenralRead'' alloziert einen Puffer für den zusammengesetzten FTX-Inhalt. Nach der Verarbeitung freigeben mit: free(peek64(result + EDI_GENRAL_BODY), peek64(result + EDI_GENRAL_BODYLEN)); ---- ===== Funktionen ===== ==== CONTRL — Syntax-Quittung ==== ^ Signatur ^ Beschreibung ^ | ''EdiContrlOk(icRef: int64, senderId: int64, receiverId: int64, out: int64, outMax: int64): int64'' | Schreibt positive CONTRL-Quittung (UCI-Status 7) | | ''EdiContrlErr(icRef: int64, segPos: int64, errCode: int64, out: int64, outMax: int64): int64'' | Schreibt negative CONTRL-Quittung mit Fehlerposition und -Code | | ''EdiContrlRead(buf: int64, bufLen: int64, result: int64): int64'' | Parst CONTRL; befüllt result (EDI_CONTRL_SIZE). Gibt ''EDI_OK'' oder Fehlercode. | ==== APERAK — Anwendungs-Fehlermeldung ==== ^ Signatur ^ Beschreibung ^ | ''EdiAperakWrite(refMsgId: int64, errCode: int64, errText: int64, out: int64, outMax: int64): int64'' | Schreibt APERAK-Nachricht; ''errText'' ist null-terminiert (oder 0 für kein Text) | | ''EdiAperakRead(buf: int64, bufLen: int64, result: int64): int64'' | Parst APERAK; befüllt result (EDI_APERAK_SIZE) | ==== GENRAL — Freitext-Nachricht ==== ^ Signatur ^ Beschreibung ^ | ''EdiGenralWrite(subject: int64, body: int64, refMsgId: int64, out: int64, outMax: int64): int64'' | Schreibt GENRAL; ''body'' wird als FTX-Segmente eingebettet | | ''EdiGenralRead(buf: int64, bufLen: int64, result: int64): int64'' | Parst GENRAL; **alloziert Puffer für Body** — nach Gebrauch freigeben | ---- ===== Auswertung einer eingehenden Quittung ===== import std.edi.messages; import std.alloc; import std.string; fn main(): int64 { var out: int64 := alloc(2048); var n: int64 := EdiContrlErr("IC000042"c, 5, EDI_ERR_INVALID_VALUE, out, 2048); var res: int64 := alloc(EDI_CONTRL_SIZE); EdiContrlRead(out, n, res); if (peek64(res + EDI_CONTRL_STATUS) == EDI_CONTRL_ACCEPTED) { PrintLn("Interchange akzeptiert."); } else { PrintLn(StrConcat("Interchange abgelehnt, Fehlercode: ", IntToStr(peek64(res + EDI_CONTRL_ERRCODE)))); PrintLn(StrConcat("Fehlerhaftes Segment: ", IntToStr(peek64(res + EDI_CONTRL_SEGPOS)))); } free(res, EDI_CONTRL_SIZE); free(out, 2048); return 0; } Interchange abgelehnt, Fehlercode: 14 Fehlerhaftes Segment: 5 ---- ===== Hinweise ===== * **Reihenfolge im Betrieb**: erst CONTRL (Syntax), dann — falls die Nachricht syntaktisch in Ordnung war, fachlich aber scheitert — APERAK. Eine fachliche Ablehnung ersetzt die Syntaxquittung nicht. * **''EdiAperakWrite'' kürzt den Fehlertext** auf ''EDI_FTX_MAX'' (512 Zeichen). * **GENRAL-Body ist alloziert**: ''EdiGenralRead'' legt für den zusammengesetzten FTX-Text einen eigenen Puffer an. Nach Gebrauch mit ''%%free(peek64(result + EDI_GENRAL_BODY), peek64(result + EDI_GENRAL_BODYLEN))%%'' freigeben — das ist die einzige Stelle in ''std.edi'', an der die Bibliothek selbst alloziert. * **Alle Text-Parameter sind Zeiger auf nullterminierten Text** (''%%"IC000042"c as int64%%''); nur ''segPos'' und ''errCode'' sind echte Zahlen. ---- ===== Quelldatei ===== ^ Unit ^ Datei ^ | ''std.edi.messages'' | ''std/edi/messages.lyx'' | Letzte Aktualisierung: 2026-08-13 — Beispiele lauffähig gemacht und ausgeführt (lyxc 1.0.17K); festgehalten, dass CONTRL einen vollständigen Interchange erzeugt (Fachnachrichten dagegen nur den Rumpf) und dass ''EdiContrlErr'' keine Partner-IDs setzt Codebeispiele geprüft: gegen **lyxc 1.2.5C** übersetzt (Prüflauf 2026-09-08 über die gesamte Doku: 574 Vollprogramme, 0 echte Fehler; zusätzlich 5159 Aufrufe gegen die ''pub fn''-Signaturen in ''aurum/std'' gehalten, 0 Abweichungen).