====== 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).