std.edi.customs

Zoll-Nachrichten per EDIFACT für den grenzüberschreitenden Warenverkehr. Alle vier Nachrichtentypen teilen denselben Header (EDI_CUS_HDR) mit Absender, Empfänger, Herkunfts-/Zielort, Zollbehörde-Referenz und Zollwert.

  • CUSCAR (BGM 85) — Customs Cargo Report: Carrier meldet Ladung bei Zollbehörde
  • CUSDEC (BGM 960) — Customs Declaration: Anmeldung durch Zollanmelder
  • CUSEXP (BGM 962) — Customs Express: Express-Sendungsmanifest (Kurier)
  • CUSRSP (BGM 961) — Customs Response: Antwort der Zollbehörde

CUSRSP-Statuscodes:

Konstante Wert Bedeutung
EDI_CUSRSP_ACCEPTED 1 Anmeldung akzeptiert
EDI_CUSRSP_REJECTED 2 Anmeldung abgelehnt
EDI_CUSRSP_QUERIED 3 Rückfrage / weitere Informationen benötigt
EDI_CUSRSP_RELEASED 4 Waren freigegeben

import std.edi.customs;
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_CUS_HDR_SIZE);
    var i: int64 := 0;
    while (i < EDI_CUS_HDR_SIZE) { poke8(hdr + i, 0); i := i + 1; }
    poke64(hdr + EDI_CUS_HDR_REF,        "ZOLL-2026-0042"c as int64);
    poke64(hdr + EDI_CUS_HDR_REFLEN,     14);
    poke64(hdr + EDI_CUS_HDR_DATE,       "20260813"c as int64);
    poke64(hdr + EDI_CUS_HDR_DATELEN,    8);
    poke64(hdr + EDI_CUS_HDR_ORIGIN,     "CNSHA"c as int64);      // Shanghai
    poke64(hdr + EDI_CUS_HDR_ORIGLEN,    5);
    poke64(hdr + EDI_CUS_HDR_DEST,       "DEHAM"c as int64);      // Hamburg
    poke64(hdr + EDI_CUS_HDR_DESTLEN,    5);
    poke64(hdr + EDI_CUS_HDR_DECLARANT,  "Muster Handel GmbH"c as int64);
    poke64(hdr + EDI_CUS_HDR_DECLLEN,    18);
    poke64(hdr + EDI_CUS_HDR_CARRIER,    "Reederei Nord"c as int64);
    poke64(hdr + EDI_CUS_HDR_CARRLEN,    13);
    poke64(hdr + EDI_CUS_HDR_CUSTVALUE,  1250000);                // 12.500,00 EUR
    poke64(hdr + EDI_CUS_HDR_CURRENCY,   "EUR"c as int64);
    poke64(hdr + EDI_CUS_HDR_CURLEN,     3);
    poke64(hdr + EDI_CUS_HDR_PROCCODE,   4000);                   // Ueberfuehrung freier Verkehr

    var items: int64 := alloc(2 * EDI_CUS_ITEM_SIZE);
    i := 0;
    while (i < 2 * EDI_CUS_ITEM_SIZE) { poke8(items + i, 0); i := i + 1; }
    poke64(items + EDI_CUS_ITEM_DESC,      "Kaffee geroestet"c as int64);
    poke64(items + EDI_CUS_ITEM_DESCLEN,   16);
    poke64(items + EDI_CUS_ITEM_QTY,       500);
    poke64(items + EDI_CUS_ITEM_VALUE,     900000);
    poke64(items + EDI_CUS_ITEM_HSCODE,    "09012100"c as int64);
    poke64(items + EDI_CUS_ITEM_HSCODELEN, 8);
    var it1: int64 := items + EDI_CUS_ITEM_SIZE;
    poke64(it1 + EDI_CUS_ITEM_DESC,      "Teemischung"c as int64);
    poke64(it1 + EDI_CUS_ITEM_DESCLEN,   11);
    poke64(it1 + EDI_CUS_ITEM_QTY,       200);
    poke64(it1 + EDI_CUS_ITEM_VALUE,     350000);
    poke64(it1 + EDI_CUS_ITEM_HSCODE,    "09024000"c as int64);
    poke64(it1 + EDI_CUS_ITEM_HSCODELEN, 8);

    var out: int64 := alloc(4096);
    var n: int64 := EdiCusdecWrite(hdr, items, 2, out, 4096);
    PrintLn(Feld(out, n));

    var hdr2: int64 := alloc(EDI_CUS_HDR_SIZE);
    var it2:  int64 := alloc(8 * EDI_CUS_ITEM_SIZE);
    var cnt: int64 := EdiCusdecRead(out, n, hdr2, it2, 8);
    PrintLn(StrConcat(StrConcat("Positionen: ", IntToStr(cnt)),
            StrConcat("  Zollwert/100: ", IntToStr(peek64(hdr2 + EDI_CUS_HDR_CUSTVALUE)))));

    // Behoerdenantwort: Ware freigegeben
    var rsp: int64 := alloc(EDI_CUS_HDR_SIZE);
    i := 0;
    while (i < EDI_CUS_HDR_SIZE) { poke8(rsp + i, 0); i := i + 1; }
    poke64(rsp + EDI_CUS_HDR_REF,        "RSP-2026-0042"c as int64);
    poke64(rsp + EDI_CUS_HDR_REFLEN,     13);
    poke64(rsp + EDI_CUS_HDR_DECLREF,    "ZOLL-2026-0042"c as int64);
    poke64(rsp + EDI_CUS_HDR_DECLREFLEN, 14);
    poke64(rsp + EDI_CUS_HDR_RSPCODE,    EDI_CUSRSP_RELEASED);
    n := EdiCusrspWrite(rsp, out, 4096);
    PrintLn(Feld(out, n));

    var rsp2: int64 := alloc(EDI_CUS_HDR_SIZE);
    EdiCusrspRead(out, n, rsp2);
    var code: int64 := peek64(rsp2 + EDI_CUS_HDR_RSPCODE);
    if (code == EDI_CUSRSP_RELEASED) { PrintLn("Ware freigegeben"); }
    if (code == EDI_CUSRSP_REJECTED) { PrintLn("Anmeldung abgelehnt"); }
    return 0;
}

BGM+960+ZOLL-2026-0042+9'DTM+137:20260813:102'LOC+87+CNSHA::9'LOC+88+DEHAM::9'NAD+DT+Muster Handel GmbH::9'NAD+CA+Reederei Nord::9'CUX+2:EUR:4'MOA+126:12500.00'GIS+4000'LIN+1+Kaffee geroestet'QTY+1:500'MOA+66:9000.00'RFF+HS:09012100'LIN+2+Teemischung'QTY+1:200'MOA+66:3500.00'RFF+HS:09024000'CNT+2:2'
Positionen: 2  Zollwert/100: 1250000
BGM+961+RSP-2026-0042+9'RFF+ADE:ZOLL-2026-0042'STS+4'CNT+2:1'
Ware freigegeben

LOC+87 ist der Abgangs-, LOC+88 der Bestimmungsort (UN/LOCODE), GIS trägt den Zollverfahrenscode, MOA+126 den Gesamt- und MOA+66 den Positionszollwert. Die Behördenantwort besteht aus RFF+ADE (Bezug zur Anmeldung) und STS mit dem Statuscode.


Imports

  • std.edi.core
  • std.alloc

Structs

EdiCusHdr (EDI_CUS_HDR_SIZE = 160 Bytes)

Offset-Konstante Inhalt
EDI_CUS_HDR_BGMQUAL BGM-Qualifier (EDI_CUS_BGM_*)
EDI_CUS_HDR_REF / EDI_CUS_HDR_REFLEN Referenz/Dokumentnummer
EDI_CUS_HDR_DATE / EDI_CUS_HDR_DATELEN Datum
EDI_CUS_HDR_ORIGIN / EDI_CUS_HDR_ORIGLEN Herkunftsland (LOC+87, z. B. „CN“)
EDI_CUS_HDR_DEST / EDI_CUS_HDR_DESTLEN Bestimmungsland (LOC+88, z. B. „DE“)
EDI_CUS_HDR_DECLARANT / EDI_CUS_HDR_DECLLEN Zollanmelder (NAD+DT)
EDI_CUS_HDR_CARRIER / EDI_CUS_HDR_CARRLEN Beförderer (NAD+CA)
EDI_CUS_HDR_CUSTVALUE Zollwert × 100 (MOA+126)
EDI_CUS_HDR_CURRENCY / EDI_CUS_HDR_CURLEN Währungscode
EDI_CUS_HDR_DECLREF / EDI_CUS_HDR_DECLREFLEN Zollanmeldungsnummer (RFF+ADE)
EDI_CUS_HDR_RSPCODE CUSRSP-Statuscode (1–4)
EDI_CUS_HDR_PROCCODE Zollverfahrenscode

EdiCusItem (EDI_CUS_ITEM_SIZE = 48 Bytes)

Offset-Konstante Inhalt
EDI_CUS_ITEM_DESC / EDI_CUS_ITEM_DESCLEN Warenbeschreibung (LIN)
EDI_CUS_ITEM_QTY Menge
EDI_CUS_ITEM_VALUE Positionswert × 100 (MOA+66)
EDI_CUS_ITEM_HSCODE / EDI_CUS_ITEM_HSCODELEN HS-Zolltarifnummer (RFF+HS)

Funktionen

Write-Funktion Read-Funktion Beschreibung
EdiCuscarWrite(hdr, items, itemCount, out, outMax) EdiCuscarRead(buf, bufLen, hdr, items, maxItems) Cargo Report
EdiCusdecWrite(hdr, items, itemCount, out, outMax) EdiCusdecRead(buf, bufLen, hdr, items, maxItems) Zollanmeldung
EdiCusexpWrite(hdr, items, itemCount, out, outMax) EdiCusexpRead(buf, bufLen, hdr, items, maxItems) Express-Manifest
EdiCusrspWrite(hdr, out, outMax) EdiCusrspRead(buf, bufLen, hdr) Zollantwort (kein Item-Array)

Alle Write-Funktionen setzen automatisch den BGM-Qualifier. Read-Funktionen geben die Anzahl der Items zurück (für CUSRSP: 1=ok, 0=Fehler).


Hinweise

  • HS-Code (RFF+HS): Die 6- bis 10-stellige HS-Zolltarifnummer identifiziert die Warengruppe international. Korrekte HS-Codes sind Voraussetzung für den automatisierten Zollabschluss.
  • Zollwert (MOA+126): Muss in der Währung aus CUX angegeben werden. Festkomma × 100.
  • CUSRSP ohne Items: EdiCusrspWrite/Read hat kein Item-Array — die Antwort bezieht sich immer auf die gesamte Anmeldung. Pflichtfelder sind EDI_CUS_HDR_DECLREF (Bezug zur Anmeldung) und EDI_CUS_HDR_RSPCODE.
  • Statuscodes der Antwort: EDI_CUSRSP_ACCEPTED (1) angenommen, EDI_CUSRSP_REJECTED (2) abgelehnt, EDI_CUSRSP_QUERIED (3) Rückfrage, EDI_CUSRSP_RELEASED (4) Ware freigegeben.
  • BGM-Qualifier setzt die Bibliothek selbst: EdiCuscarWrite schreibt 85, EdiCusdecWrite 960, EdiCusexpWrite 962, EdiCusrspWrite 961 — ein selbst gesetzter EDI_CUS_HDR_BGMQUAL wird überschrieben. Alle vier Nachrichten teilen sich denselben Kopf-Struct.
  • Alle vier Nachrichten nutzen dieselben Item-Structs; für CUSCAR (Frachtanmeldung) ist die Warenbeschreibung Pflicht, für CUSDEC zusätzlich der HS-Code.

Quelldatei

Unit Datei
std.edi.customs std/edi/customs.lyx

Letzte Aktualisierung: 2026-08-13 — ein durchgehendes, lauffähiges Beispiel (Zollanmeldung → Behördenantwort) mit echter Ausgabe (lyxc 1.0.17K); Statuscodes und das automatische Setzen des BGM-Qualifiers dokumentiert

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