====== std.edi.seafreight ====== Seefrachtsteuerung per EDIFACT: Stauplan, Containeranweisungen, Bekanntmachungen und Gewichtsangaben. Alle 9 Nachrichtentypen verwenden denselben Header (EDI_SF_HDR) und dieselbe Containerstruktur (EDI_SF_CONT_SIZE = 80 Bytes). Container-IDs werden nach ISO 6346 (11-stellig) validiert. * **BAPLIE** (BGM 23) — Bay Plan with Loading Information: Stauplan des Schiffes (Position je Container) * **MOVINS** (BGM 28) — Stowage Instruction: Staupläne für Be-/Entladung * **COPARN** (BGM 38) — Container Pre-Arrival Notification: Anmeldung vor Einlauf * **CODECO** (BGM 29) — Container Gate-In/-Out: Ein-/Ausgangsmeldung am Terminal * **COARRI** (BGM 30) — Container Arrival/Departure: Ankunfts-/Abfahrtsmeldung * **COPINO** (BGM 39) — Container Pre-Notification: Voranmeldung für Pick-up * **COPRAR** (BGM 42) — Container Pre-Advice of Release: Freigabemitteilung * **VERMAS** (BGM 35) — Verified Mass: Verifiziertes Bruttogewicht (VGM, SOLAS-Pflicht) * **HANMOV** (BGM 85) — Handling Movement: Umschlagsanweisung (Shift/Transfer) Bewegungstypen: ^ Konstante ^ Wert ^ Bedeutung ^ | ''EDI_SF_MOVE_LOAD'' | 1 | Verladen | | ''EDI_SF_MOVE_DISCHARGE'' | 2 | Entladen | | ''EDI_SF_MOVE_SHIFT'' | 3 | Umlagern | import std.edi.seafreight; 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_SF_HDR_SIZE); var i: int64 := 0; while (i < EDI_SF_HDR_SIZE) { poke8(hdr + i, 0); i := i + 1; } poke64(hdr + EDI_SF_HDR_REF, "STAU-2026-08"c as int64); poke64(hdr + EDI_SF_HDR_REFLEN, 12); poke64(hdr + EDI_SF_HDR_DATE, "20260813"c as int64); poke64(hdr + EDI_SF_HDR_DATELEN, 8); poke64(hdr + EDI_SF_HDR_VESSEL, "MV NORDLICHT"c as int64); poke64(hdr + EDI_SF_HDR_VESSELLN, 12); poke64(hdr + EDI_SF_HDR_VOYAGE, "V2608E"c as int64); poke64(hdr + EDI_SF_HDR_VOYAGELN, 6); poke64(hdr + EDI_SF_HDR_PORT, "DEHAM"c as int64); poke64(hdr + EDI_SF_HDR_PORTLEN, 5); var conts: int64 := alloc(2 * EDI_SF_CONT_SIZE_OFF); i := 0; while (i < 2 * EDI_SF_CONT_SIZE_OFF) { poke8(conts + i, 0); i := i + 1; } poke64(conts + EDI_SF_CONT_ID, "MSKU1234565"c as int64); poke64(conts + EDI_SF_CONT_IDLEN, 11); poke64(conts + EDI_SF_CONT_SIZE, 40); poke64(conts + EDI_SF_CONT_TYPE, "GP"c as int64); poke64(conts + EDI_SF_CONT_TYPELEN, 2); poke64(conts + EDI_SF_CONT_BAY, 14); poke64(conts + EDI_SF_CONT_ROW, 3); poke64(conts + EDI_SF_CONT_TIER, 82); poke64(conts + EDI_SF_CONT_WEIGHT, 2418000); // 24.180,00 kg poke64(conts + EDI_SF_CONT_MOVETYPE, EDI_SF_MOVE_LOAD); var c1: int64 := conts + EDI_SF_CONT_SIZE_OFF; poke64(c1 + EDI_SF_CONT_ID, "TGHU7654321"c as int64); poke64(c1 + EDI_SF_CONT_IDLEN, 11); poke64(c1 + EDI_SF_CONT_SIZE, 20); poke64(c1 + EDI_SF_CONT_TYPE, "RF"c as int64); poke64(c1 + EDI_SF_CONT_TYPELEN, 2); poke64(c1 + EDI_SF_CONT_BAY, 6); poke64(c1 + EDI_SF_CONT_ROW, 1); poke64(c1 + EDI_SF_CONT_TIER, 84); poke64(c1 + EDI_SF_CONT_WEIGHT, 1810000); poke64(c1 + EDI_SF_CONT_MOVETYPE, EDI_SF_MOVE_DISCHARGE); // Containernummern vor dem Versand pruefen (ISO 6346) PrintLn(StrConcat("MSKU1234565 gueltig: ", IntToStr(EdiContainerCheck("MSKU1234565"c, 11)))); var out: int64 := alloc(4096); var n: int64 := EdiBaplieWrite(hdr, conts, 2, out, 4096); PrintLn(Feld(out, n)); var hdr2: int64 := alloc(EDI_SF_HDR_SIZE); var co2: int64 := alloc(8 * EDI_SF_CONT_SIZE_OFF); var cnt: int64 := EdiBaplieRead(out, n, hdr2, co2, 8); PrintLn(StrConcat("Container im Stauplan: ", IntToStr(cnt))); // VERMAS: verifiziertes Bruttogewicht (SOLAS) n := EdiVermasWrite(hdr, conts, 1, out, 4096); PrintLn(Feld(out, n)); return 0; } MSKU1234565 gueltig: 1 BGM+23+STAU-2026-08+9'DTM+137:20260813:102'TDT+20++MV NORDLICHT'RFF+VN:V2608E'LOC+9+DEHAM::9'EQD+CN+MSKU1234565+40:GP'LOC+147+14:3:82'MEA+VGM+WT:KGM:24180.00'TSR+1'EQD+CN+TGHU7654321+20:RF'LOC+147+6:1:84'MEA+VGM+WT:KGM:18100.00'TSR+2'CNT+2:2' Container im Stauplan: 2 BGM+35+STAU-2026-08+9'DTM+137:20260813:102'TDT+20++MV NORDLICHT'RFF+VN:V2608E'LOC+9+DEHAM::9'EQD+CN+MSKU1234565+40:GP'LOC+147+14:3:82'MEA+VGM+WT:KGM:24180.00'TSR+1'CNT+2:1' Alle neun Seefracht-Nachrichten teilen sich Kopf- und Container-Struct; sie unterscheiden sich nur im BGM-Qualifier, den die jeweilige ''…Write''-Funktion selbst setzt. ''EQD+CN'' trägt Containernummer, Größe und Typ, ''LOC+147'' die Stauposition Bay:Row:Tier, ''MEA+VGM'' das verifizierte Bruttogewicht und ''TSR'' die Bewegungsart. ---- ===== Imports ===== * ''std.edi.core'' * ''std.alloc'' ---- ===== Structs ===== ==== EdiSfHdr (EDI_SF_HDR_SIZE = 96 Bytes) ==== ^ Offset-Konstante ^ Inhalt ^ | ''EDI_SF_HDR_BGMQUAL'' | BGM-Qualifier (automatisch gesetzt) | | ''EDI_SF_HDR_REF / EDI_SF_HDR_REFLEN'' | Dokumentreferenz | | ''EDI_SF_HDR_DATE / EDI_SF_HDR_DATELEN'' | Datum | | ''EDI_SF_HDR_VESSEL / EDI_SF_HDR_VESSELLN'' | Schiffsname (TDT+20) | | ''EDI_SF_HDR_VOYAGE / EDI_SF_HDR_VOYAGELN'' | Reise-/Voyage-Nummer (RFF+VN) | | ''EDI_SF_HDR_PORT / EDI_SF_HDR_PORTLEN'' | Hafen (LOC+9, UN/LOCODE) | | ''EDI_SF_HDR_MOVECOUNT'' | Anzahl Container (CNT) | ==== EdiSfContainer (EDI_SF_CONT_SIZE = 80 Bytes) ==== ^ Offset-Konstante ^ Inhalt ^ | ''EDI_SF_CONT_ID / EDI_SF_CONT_IDLEN'' | Container-ID nach ISO 6346 (11 Zeichen) | | ''EDI_SF_CONT_SIZE_FT'' | Containermaß in Fuß (z. B. 20, 40, 45) | | ''EDI_SF_CONT_TYPE / EDI_SF_CONT_TYPELEN'' | ISO-Containertyp-Code (z. B. "GP", "RF", "OT") | | ''EDI_SF_CONT_BAY'' | Bay-Position (Ladeposition im Schiff) | | ''EDI_SF_CONT_ROW'' | Row-Position | | ''EDI_SF_CONT_TIER'' | Tier-Position | | ''EDI_SF_CONT_WEIGHT'' | Bruttogewicht × 100 in kg (MEA+VGM+WT:KGM) | | ''EDI_SF_CONT_MOVETYPE'' | Bewegungstyp: 1=Load, 2=Discharge, 3=Shift | Wire-Format pro Container: ''EQD+CN+id+size:type'' → ''LOC+147+bay:row:tier'' → ''MEA+VGM+WT:KGM+weight'' → ''TSR+moveType''. ---- ===== ISO 6346 Container-Validierung ===== ^ Signatur ^ Beschreibung ^ | ''EdiContainerCheck(ptr: int64, len: int64): int64'' | Prüft ISO-6346-Prüfziffer (11-stellig). Buchstaben A–Z werden auf 10–35 abgebildet (11/22/33 übersprungen); Gewichte 2⁰…2⁹; Prüfziffer = (Summe % 11) % 10. Gibt 1=gültig, 0=ungültig. | ISO-6346-Format: 4 Buchstaben Prefix (z. B. "TCKU") + 6 Ziffern Seriennummer + 1 Prüfziffer, z. B. ''TCKU342567**8**''. ---- ===== Funktionen ===== Alle 9 Nachrichtentypen teilen dieselbe Signatur: ^ Write-Funktion ^ Read-Funktion ^ Beschreibung ^ | ''EdiBaplieWrite(hdr, conts, contCount, out, outMax)'' | ''EdiBaplieRead(buf, bufLen, hdr, conts, maxConts)'' | Stauplan | | ''EdiMovinsWrite(hdr, conts, contCount, out, outMax)'' | ''EdiMovinsRead(buf, bufLen, hdr, conts, maxConts)'' | Staupläne Be-/Entladung | | ''EdiCoparnWrite(hdr, conts, contCount, out, outMax)'' | ''EdiCoparnRead(buf, bufLen, hdr, conts, maxConts)'' | Voranmeldung Einlauf | | ''EdiCodecoWrite(hdr, conts, contCount, out, outMax)'' | ''EdiCodecoRead(buf, bufLen, hdr, conts, maxConts)'' | Gate-In/-Out | | ''EdiCoarriWrite(hdr, conts, contCount, out, outMax)'' | ''EdiCoarriRead(buf, bufLen, hdr, conts, maxConts)'' | Ankunfts-/Abfahrtsmeldung | | ''EdiCopinoWrite(hdr, conts, contCount, out, outMax)'' | ''EdiCopinoRead(buf, bufLen, hdr, conts, maxConts)'' | Voranmeldung Pick-up | | ''EdiCoprarWrite(hdr, conts, contCount, out, outMax)'' | ''EdiCoprarRead(buf, bufLen, hdr, conts, maxConts)'' | Freigabemitteilung | | ''EdiVermasWrite(hdr, conts, contCount, out, outMax)'' | ''EdiVermasRead(buf, bufLen, hdr, conts, maxConts)'' | VGM-Gewicht (SOLAS) | | ''EdiHanmovWrite(hdr, conts, contCount, out, outMax)'' | ''EdiHanmovRead(buf, bufLen, hdr, conts, maxConts)'' | Umschlagsanweisung | Alle Read-Funktionen geben die Anzahl der gelesenen Container zurück. Zero-Copy: Zeiger in ''conts'' zeigen in ''buf''. ---- ===== Hinweise ===== * **VGM SOLAS-Pflicht**: Seit 2016 müssen alle Container vor Verladung ein verifiziertes Bruttogewicht (VGM) vorweisen. ''EdiVermasWrite'' erzeugt den entsprechenden EDIFACT-Austausch. * **Bay/Row/Tier**: Die Stauposition in BAPLIE/MOVINS wird als dreistellige Ortsangabe kodiert (LOC+147). Bay = Schiffslängsachse, Row = Querachse, Tier = Höhe. * **CODECO Ein-/Ausgang**: Beim Gate-In wird ''EDI_SF_MOVE_LOAD'' verwendet, beim Gate-Out ''EDI_SF_MOVE_DISCHARGE''. ''EDI_SF_MOVE_SHIFT'' steht für interne Terminalumlagerungen. * **UN/LOCODE Häfen**: ''EDI_SF_HDR_PORT'' erwartet einen 5-stelligen UN/LOCODE (z. B. "DEHAM" = Hamburg, "CNSHA" = Shanghai). * **Gewicht ist ×100 in Kilogramm**: ''2418000'' ergibt ''MEA+VGM+WT:KGM:24180.00'' — also 24,18 Tonnen. * **Struct-Größe heißt ''EDI_SF_CONT_SIZE_OFF''** (80 Bytes). ''EDI_SF_CONT_SIZE'' ist dagegen das **Feld** für die Containergröße in Fuß (20/40) — die beiden Namen sind leicht zu verwechseln. * **Containernummer selbst prüfen**: ''EdiContainerCheck'' (ISO 6346) wird von keiner Write-Funktion aufgerufen. ---- ===== Quelldatei ===== ^ Unit ^ Datei ^ | ''std.edi.seafreight'' | ''std/edi/seafreight.lyx'' | Letzte Aktualisierung: 2026-08-13 — lauffähiges Beispiel für BAPLIE (Stauplan mit zwei Containern) und VERMAS mit echter Ausgabe (lyxc 1.0.17K); Hinweise zu Gewichtsskalierung und der Namensfalle ''EDI_SF_CONT_SIZE'' vs. ''EDI_SF_CONT_SIZE_OFF'' ergänzt 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).