====== std.edi.transport ====== Multimodaler Transportauftrag und Sendungsstatus per EDIFACT. Alle 8 Nachrichtentypen teilen denselben Header (EDI_TRN_HDR). IFTMIN beschreibt den vollständigen Transportauftrag mit beliebig vielen Beförderungsabschnitten (Legs). IFTDGN enthält Gefahrgutinformationen (DGD-Struct). IFTSTA übermittelt den Sendungsstatus. * **IFTMIN** (BGM 310) — Instruction for the Movement of Goods: Transportauftrag mit Legs * **IFTMBC** (BGM 311) — Response to IFTMIN: Auftragsbestätigung/-ablehnung * **IFTMCS** (BGM 312) — Instruction Contract Status: Vertragsstatus * **IFTMAN** (BGM 313) — Arrival Notice: Ankündigungsmeldung * **IFCSUM** (BGM 319) — Freight Invoice: Frachtabrechnung * **IFTSTA** (BGM 214) — Status: Sendungsstatus * **IFTDGN** (BGM 350) — Dangerous Goods Notification: Gefahrgutmeldung * **IFTFCC** (BGM 315) — Freight Costs and other Charges: Frachtkosten (Buchungsreferenz Pflicht) IFTSTA-Statuscodes: ^ Konstante ^ Wert ^ Bedeutung ^ | ''EDI_TRN_STA_PICKEDUP'' | 1 | Abgeholt | | ''EDI_TRN_STA_INTRANSIT'' | 2 | Unterwegs | | ''EDI_TRN_STA_DELAYED'' | 3 | Verzögert | | ''EDI_TRN_STA_DELIVERED'' | 4 | Zugestellt | Transportmodi (IFTMIN Legs): ^ Wert ^ Bedeutung ^ | 1 | See | | 2 | Schiene | | 3 | Straße | | 4 | Luft | import std.edi.transport; 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 hdr: int64 := alloc(EDI_TRN_HDR_SIZE); var i: int64 := 0; while (i < EDI_TRN_HDR_SIZE) { poke8(hdr + i, 0); i := i + 1; } poke64(hdr + EDI_TRN_HDR_REF, "TRP-2026-0815"c as int64); poke64(hdr + EDI_TRN_HDR_REFLEN, 13); poke64(hdr + EDI_TRN_HDR_DATE, "20260813"c as int64); poke64(hdr + EDI_TRN_HDR_DATELEN, 8); poke64(hdr + EDI_TRN_HDR_DEPARTURE, "CNSHA"c as int64); poke64(hdr + EDI_TRN_HDR_DEPLEN, 5); poke64(hdr + EDI_TRN_HDR_ARRIVAL, "DEMUC"c as int64); poke64(hdr + EDI_TRN_HDR_ARRLEN, 5); poke64(hdr + EDI_TRN_HDR_CARRIER, "Spedition Nord"c as int64); poke64(hdr + EDI_TRN_HDR_CARRLEN, 14); poke64(hdr + EDI_TRN_HDR_BOOKINGREF, "BK-99001"c as int64); poke64(hdr + EDI_TRN_HDR_BOOKINGLEN, 8); // Drei Teilstrecken: See, Bahn, Strasse var legs: int64 := alloc(3 * EDI_TRN_LEG_SIZE); i := 0; while (i < 3 * EDI_TRN_LEG_SIZE) { poke8(legs + i, 0); i := i + 1; } poke64(legs + EDI_TRN_LEG_DEPARTURE, "CNSHA"c as int64); poke64(legs + EDI_TRN_LEG_DEPLEN, 5); poke64(legs + EDI_TRN_LEG_ARRIVAL, "DEHAM"c as int64); poke64(legs + EDI_TRN_LEG_ARRLEN, 5); poke64(legs + EDI_TRN_LEG_MODE, 1); // 1 = See var g1: int64 := legs + EDI_TRN_LEG_SIZE; poke64(g1 + EDI_TRN_LEG_DEPARTURE, "DEHAM"c as int64); poke64(g1 + EDI_TRN_LEG_DEPLEN, 5); poke64(g1 + EDI_TRN_LEG_ARRIVAL, "DENUE"c as int64); poke64(g1 + EDI_TRN_LEG_ARRLEN, 5); poke64(g1 + EDI_TRN_LEG_MODE, 2); // 2 = Bahn var g2: int64 := legs + 2 * EDI_TRN_LEG_SIZE; poke64(g2 + EDI_TRN_LEG_DEPARTURE, "DENUE"c as int64); poke64(g2 + EDI_TRN_LEG_DEPLEN, 5); poke64(g2 + EDI_TRN_LEG_ARRIVAL, "DEMUC"c as int64); poke64(g2 + EDI_TRN_LEG_ARRLEN, 5); poke64(g2 + EDI_TRN_LEG_MODE, 3); // 3 = Strasse var out: int64 := alloc(4096); var n: int64 := EdiIftminWrite(hdr, legs, 3, out, 4096); PrintLn(Feld(out, n)); var hdr2: int64 := alloc(EDI_TRN_HDR_SIZE); var lg2: int64 := alloc(8 * EDI_TRN_LEG_SIZE); var cnt: int64 := EdiIftminRead(out, n, hdr2, lg2, 8); PrintLn(StrConcat("Teilstrecken: ", IntToStr(cnt))); // Statusmeldung: unterwegs poke64(hdr + EDI_TRN_HDR_STATUSCODE, EDI_IFTSTA_INTRANSIT); n := EdiIftstaWrite(hdr, out, 4096); PrintLn(Feld(out, n)); // Pruef-Funktionen melden Fehler, nicht Erfolg: 0 = in Ordnung PrintLn(StrConcat("Statuspruefung (0 = ok): ", IntToStr(EdiIftstaStatusCheck(EDI_IFTSTA_INTRANSIT)))); PrintLn(StrConcat("Statuspruefung Code 9: ", IntToStr(EdiIftstaStatusCheck(9)))); PrintLn(StrConcat("IFTFCC-Pruefung (0 = ok): ", IntToStr(EdiIftfccCheck(hdr)))); // Gefahrgutmeldung: Benzin, UN 1203 var dg: int64 := alloc(EDI_DGD_SIZE); i := 0; while (i < EDI_DGD_SIZE) { poke8(dg + i, 0); i := i + 1; } poke64(dg + EDI_DGD_UNNUMBER, "1203"c as int64); poke64(dg + EDI_DGD_UNLEN, 4); poke64(dg + EDI_DGD_IMDGCLASS, "3"c as int64); poke64(dg + EDI_DGD_IMDGLEN, 1); poke64(dg + EDI_DGD_PACKINGGROUP, 2); // II poke64(dg + EDI_DGD_EMSCODE, "F-E,S-E"c as int64); poke64(dg + EDI_DGD_EMSLEN, 7); poke64(dg + EDI_DGD_QTY, 8000); if (EdiUnNumberCheck(peek64(dg + EDI_DGD_UNNUMBER), 4) != 1) { PrintLn("UN-Nummer ungueltig"); return 1; } n := EdiIftdgnWrite(hdr, dg, 1, out, 4096); PrintLn(Feld(out, n)); return 0; } BGM+310+TRP-2026-0815+9'DTM+137:20260813:102'LOC+87+CNSHA::9'LOC+88+DEMUC::9'NAD+CA+Spedition Nord::9'TDT+1++1'LOC+9+CNSHA::9'LOC+11+DEHAM::9'TDT+2++2'LOC+9+DEHAM::9'LOC+11+DENUE::9'TDT+3++3'LOC+9+DENUE::9'LOC+11+DEMUC::9'CNT+2:3' Teilstrecken: 3 BGM+214+TRP-2026-0815+9'DTM+137:20260813:102'LOC+87+CNSHA::9'LOC+88+DEMUC::9'NAD+CA+Spedition Nord::9'STS+2'CNT+2:1' Statuspruefung (0 = ok): 0 Statuspruefung Code 9: 1 IFTFCC-Pruefung (0 = ok): 0 BGM+350+TRP-2026-0815+9'DTM+137:20260813:102'LOC+87+CNSHA::9'LOC+88+DEMUC::9'NAD+CA+Spedition Nord::9'DGS+ADR+1203+3+2+F-E,S-E'CNT+2:1' Jede Teilstrecke wird als ''TDT''-Segment mit Verkehrsträger (1 See, 2 Bahn, 3 Straße, 4 Luft) und den beiden ''LOC''-Segmenten für Abgang und Ziel geschrieben. Status (''STS'') und Gefahrgut (''DGS'') nutzen denselben Kopf-Struct. ---- ===== Imports ===== * ''std.edi.core'' * ''std.alloc'' ---- ===== Structs ===== ==== EdiTrnHdr (EDI_TRN_HDR_SIZE = 112 Bytes) ==== Gemeinsamer Header für alle 8 Nachrichtentypen. ^ Offset-Konstante ^ Inhalt ^ | ''EDI_TRN_HDR_BGMQUAL'' | BGM-Qualifier (automatisch gesetzt) | | ''EDI_TRN_HDR_REF / EDI_TRN_HDR_REFLEN'' | Auftrags-/Dokumentreferenz | | ''EDI_TRN_HDR_DATE / EDI_TRN_HDR_DATELEN'' | Datum | | ''EDI_TRN_HDR_DEPARTURE / EDI_TRN_HDR_DEPARTLEN'' | Abgangspunkt (LOC+87, z. B. UN/LOCODE) | | ''EDI_TRN_HDR_ARRIVAL / EDI_TRN_HDR_ARRIVALLEN'' | Bestimmungsort (LOC+88) | | ''EDI_TRN_HDR_CARRIER / EDI_TRN_HDR_CARRIERLEN'' | Spediteur/Carrier (NAD+CA) | | ''EDI_TRN_HDR_BOOKINGREF / EDI_TRN_HDR_BOOKINGLEN'' | Buchungsreferenz (RFF+BN) — Pflicht für IFTFCC | | ''EDI_TRN_HDR_STATUSCODE'' | IFTSTA-Statuscode (1–4) | ==== EdiTrnLeg (EDI_TRN_LEG_SIZE = 40 Bytes) ==== Ein Beförderungsabschnitt innerhalb eines IFTMIN-Auftrags. IFTMIN kann beliebig viele Legs enthalten — z. B. LKW zum Hafen → Schiff → Bahn zu Empfänger. ^ Offset-Konstante ^ Inhalt ^ | ''EDI_TRN_LEG_DEPARTURE / EDI_TRN_LEG_DEPARTLEN'' | Abgangsort des Abschnitts (LOC+9) | | ''EDI_TRN_LEG_ARRIVAL / EDI_TRN_LEG_ARRIVALLEN'' | Ankunftsort des Abschnitts (LOC+11) | | ''EDI_TRN_LEG_MODE'' | Transportmodus: 1=See, 2=Schiene, 3=Straße, 4=Luft | Wire pro Leg: ''TDT+20+mode'' → ''LOC+9+departure'' → ''LOC+11+arrival''. ==== EdiDgd (EDI_DGD_SIZE = 64 Bytes) ==== Gefahrgutinformation für IFTDGN. Pro Sendung können mehrere DGD-Strukturen vorkommen. ^ Offset-Konstante ^ Inhalt ^ | ''EDI_DGD_UNNUMBER / EDI_DGD_UNNUMLEN'' | UN-Nummer (genau 4 Stellen, z. B. "1203" für Benzin) | | ''EDI_DGD_IMDGCLASS / EDI_DGD_IMDGLEN'' | IMDG-Klasse (z. B. "3", "8", "6.1") | | ''EDI_DGD_PACKINGGROUP'' | Verpackungsgruppe 1–3 (I=höchste, III=niedrigste Gefahr) | | ''EDI_DGD_EMSCODE / EDI_DGD_EMSLEN'' | EMS-Code (Emergency Schedule, z. B. "F-E,S-E") | | ''EDI_DGD_QTY'' | Menge in der Sendung | Wire: ''DGS+ADR+unNum+imdgClass+packingGroup+emsCode''. ---- ===== Validierungsfunktionen ===== ^ Signatur ^ Beschreibung ^ | ''EdiUnNumberCheck(ptr: int64, len: int64): int64'' | Prüft UN-Nummer: genau 4 Ziffern (0000–9999). Gibt 1=gültig, 0=ungültig. | | ''EdiIftstaStatusCheck(code: int64): int64'' | Prüft IFTSTA-Statuscode: 1–4 bekannt → 0; sonst 1 (Warnung, nicht Fehler). | | ''EdiIftfccCheck(hdr: int64): int64'' | Gibt 2 (Fehler) wenn keine Buchungsreferenz (''RFF+BN'') vorhanden — Pflichtfeld in IFTFCC. | ---- ===== Funktionen ===== ==== Einfache Transport-Nachrichten ==== ^ Write-Funktion ^ Read-Funktion ^ Beschreibung ^ | ''EdiIftmbcWrite(hdr, out, outMax)'' | ''EdiIftmbcRead(buf, bufLen, hdr)'' | IFTMIN-Antwort | | ''EdiIftmcsWrite(hdr, out, outMax)'' | ''EdiIftmcsRead(buf, bufLen, hdr)'' | Vertragsstatus | | ''EdiIftmanWrite(hdr, out, outMax)'' | ''EdiIftmanRead(buf, bufLen, hdr)'' | Ankunftsankündigung | | ''EdiIfcsumWrite(hdr, out, outMax)'' | ''EdiIfcsumRead(buf, bufLen, hdr)'' | Frachtabrechnung | | ''EdiIftstaWrite(hdr, out, outMax)'' | ''EdiIftstaRead(buf, bufLen, hdr)'' | Sendungsstatus | | ''EdiIftfccWrite(hdr, out, outMax)'' | ''EdiIftfccRead(buf, bufLen, hdr)'' | Frachtkosten | ==== Nachrichten mit Leg-Array (IFTMIN) ==== ^ Signatur ^ Beschreibung ^ | ''EdiIftminWrite(hdr: int64, legs: int64, legCount: int64, out: int64, outMax: int64): int64'' | Schreibt Transportauftrag mit N Beförderungsabschnitten. | | ''EdiIftminRead(buf: int64, bufLen: int64, hdr: int64, legs: int64, maxLegs: int64): int64'' | Parst IFTMIN; gibt Anzahl der Legs zurück. | ==== Gefahrgutmeldung (IFTDGN) ==== ^ Signatur ^ Beschreibung ^ | ''EdiIftdgnWrite(hdr: int64, dgds: int64, dgdCount: int64, out: int64, outMax: int64): int64'' | Schreibt Gefahrgutmeldung mit N DGD-Einträgen. | | ''EdiIftdgnRead(buf: int64, bufLen: int64, hdr: int64, dgds: int64, maxDgds: int64): int64'' | Parst IFTDGN; gibt DGD-Anzahl zurück. | ---- ===== Hinweise ===== * **IFTFCC Buchungsreferenz Pflicht**: ''EdiIftfccCheck'' gibt Fehler (2) zurück wenn keine Buchungsreferenz (''RFF+BN'') gesetzt ist. Vor ''EdiIftfccWrite'' immer prüfen. * **UN-Nummer immer 4-stellig**: ''EdiUnNumberCheck'' verlangt genau 4 Ziffern — also "0012" statt "12". Führende Nullen sind Teil der Nummer (z. B. 0004 = Ammoniumnitrat in Lösung). * **Prüf-Funktionen melden Fehler, nicht Erfolg**: ''EdiIftstaStatusCheck'' liefert **0 für einen bekannten Code** und 1 für einen unbekannten; ''EdiIftfccCheck'' 0 bei gesetzter Buchungsreferenz und 2 ohne. Wer auf ''== 1'' als „gültig" prüft, dreht die Logik um. * **Gefahrgut-Struct**: ''EDI_DGD_PACKINGGROUP'' ist eine Zahl (1 = I, 2 = II, 3 = III), UN-Nummer und IMDG-Klasse dagegen Zeiger auf Text. Alles landet in einem ''DGS+ADR''-Segment. * **Legs nur in IFTMIN**: Nur ''EdiIftminWrite/Read'' akzeptiert ein Leg-Array. Alle anderen Nachrichten haben genau einen Abgangspunkt und einen Bestimmungsort im Header. ---- ===== Quelldatei ===== ^ Unit ^ Datei ^ | ''std.edi.transport'' | ''std/edi/transport.lyx'' | Letzte Aktualisierung: 2026-08-13 — ein durchgehendes, lauffähiges Beispiel für IFTMIN (drei Teilstrecken), IFTSTA und IFTDGN mit echter Ausgabe (lyxc 1.0.17K); Rückgabekonvention der Prüf-Funktionen (0 = ok) richtiggestellt 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).