Dieser Guide erklärt den elektronischen B2B-Datenaustausch mit der Lyx-EDI-Bibliothek: von den Grundbegriffen über den Nachrichtenaufbau bis zu vollständigen Workflows für Bestellungen, Rechnungen, Lieferscheine und Zahlungsabwicklung.
→ std.edi — Übersicht · std.edi.core · Welche Unit?
Alle Beispiele dieser Seite sind mit lyxc 1.0.21A übersetzt und ausgeführt; die gezeigten Ausgaben sind echte Programmausgaben.
Die Begriffe werden im Alltag oft synonym verwendet, meinen aber unterschiedliche Dinge:
EDI (Electronic Data Interchange) ist ein Oberbegriff für den maschinellen Austausch von Geschäftsdokumenten zwischen Computersystemen — ohne manuelle Erfassung. EDI beschreibt das Konzept, nicht das Format. Unter dem Begriff EDI laufen viele Standards:
| Standard | Ursprung | Verbreitet in |
|---|---|---|
| UN/EDIFACT | UNO, seit 1987 | Europa, Asien, Logistik, Handel |
| ANSI X12 | USA, seit 1979 | Nordamerika, Gesundheitswesen, Handel |
| TRADACOMS | GS1 UK, seit 1982 | Britischer Einzelhandel (Altbestand) |
| VDA | Deutscher Automobilverband | Deutsche Automobilindustrie |
| ODETTE | Europäische Automobilindustrie | Europäischer Automobilbau |
| OpenTrans / UBL | XML-basiert, modern | E-Procurement, XRechnung |
EDIFACT (UN/EDIFACT — United Nations / Electronic Data Interchange for Administration, Commerce and Transport) ist der weltweit am häufigsten eingesetzte EDI-Standard außerhalb Nordamerikas. Er wurde von der UNO standardisiert und definiert exakt, wie eine Nachricht aufgebaut ist: Segmente, Trennzeichen, Zeichensätze, Nachrichtentypen (ORDERS, INVOIC, DESADV, …).
Lyx's std.edi implementiert UN/EDIFACT. Wenn im Lyx-Kontext von „EDI“ gesprochen wird, ist immer EDIFACT gemeint.
Eine EDIFACT-Übertragung (Interchange) ist wie ein Brief strukturiert: Umschlag außen, Inhalt innen.
UNA:+.? ' ← Trennzeichen-Definition (optional)
UNB+UNOA:1+SENDER:1+EMPFÄNGER:1+261201:0900+1' ← Interchange-Anfang
UNH+1+ORDERS:D:96A:UN:EAN008' ← Nachrichtenkopf
BGM+220+ORD-2026-001+9' ← Dokumenttyp + Nummer
DTM+137:20261201:102' ← Datum
LIN+1++04012345678901:SRV' ← Position 1 (GTIN)
QTY+21:100' ← Bestellmenge
UNT+5+1' ← Nachrichtenende (5 Segmente, Nr. 1)
UNZ+1+1' ← Interchange-Ende (1 Nachricht, Nr. 1)
Hierarchie einer EDIFACT-Übertragung:
Interchange (UNB…UNZ) ← eine Übertragung
└─ Funktionale Gruppe (UNG…UNE) ← optional; mehrere gleiche Nachrichtentypen
└─ Nachricht (UNH…UNT) ← z. B. 1 ORDERS
└─ Segmente ← BGM, DTM, LIN, QTY, MOA, …
└─ Elemente ← einzelne Felder, durch + getrennt
└─ Komponenten ← Teilfelder, durch : getrennt
Segmentnamen sind immer dreistellig. Häufige Segmente:
| Segment | Bedeutung | Beispiel |
|---|---|---|
UNA | Service String Advice — definiert Trennzeichen | UNA:+.? ' |
UNB | Interchange Header — Absender, Empfänger, Datum | UNB+UNOA:1+… |
UNZ | Interchange Trailer — Prüfsumme | UNZ+1+1' |
UNH | Message Header — Nachrichtentyp + Version | UNH+1+ORDERS:D:96A:UN' |
UNT | Message Trailer — Segmentzahl | UNT+12+1' |
BGM | Beginning of Message — Dokumenttyp + Nummer | BGM+220+ORD-001+9' |
DTM | Date/Time/Period | DTM+137:20261201:102' |
NAD | Name and Address | NAD+BY+4012345000009::9' |
LIN | Line Item | LIN+1++04012345678901:SRV' |
QTY | Quantity | QTY+21:100' |
MOA | Monetary Amount | MOA+203:1999 |
RFF | Reference | RFF+ON:ORD-2026-001' |
FTX | Free Text | FTX+AAI+++Lieferkommentar' |
EDIFACT unterstützt mehrere Zeichensätze. Der wichtigste ist UNOA:
| Zeichensatz | Zeichen | Einsatz |
|---|---|---|
| UNOA | A–Z (Großbuchstaben), 0–9, Leerzeichen, Sonderzeichen | Standard, B2B-Handel, sichere Wahl |
| UNOB | Wie UNOA + a–z (Kleinbuchstaben) | Erweiterter ASCII |
| UNOC | ISO 8859-1 (Latin-1, Umlaute) | Deutschland/Österreich/Schweiz |
Lyx setzt standardmäßig UNOA. Der Zeichensatz wird im UNB-Segment angegeben und durch EdiUnaRead aus der eingehenden Nachricht gelesen.
Standard-Trennzeichen (UNOA):
| Komponenten-Trennzeichen | : (Doppelpunkt) |
| Datenelement-Trennzeichen | + (Plus) |
| Dezimalzeichen | . (Punkt) |
| Escape-Zeichen (Release) | ? (Fragezeichen) |
| Segment-Abschlusszeichen | (Apostroph) |
Das Escape-Zeichen ? maskiert Sonderzeichen innerhalb von Feldern. ?+ bedeutet ein wörtliches +, nicht ein Trennzeichen.
Die 14 EDI-Units decken alle Phasen einer Lieferkette ab:
Stammdaten → std.edi.catalog (PRICAT, PARTIN)
Partner → std.edi.partner (AS2/SFTP-Profile)
Anfrage → std.edi.rfq (REQOTE, QUOTES)
Bestellung → std.edi.orders (ORDERS, ORDRSP, ORDCHG)
Lieferung → std.edi.shipping (DESADV, RECADV)
Inventar → std.edi.inventory (INVRPT, SLSRPT, SLSFCT)
Lieferabruf → std.edi.delfor (DELFOR, DELJIT)
Rechnung → std.edi.invoice (INVOIC, INVCON, COMDIS, COACSU)
Zahlung → std.edi.payment (REMADV, PAYMUL, PAYORD, DIRDEB, …)
Zoll → std.edi.customs (CUSCAR, CUSDEC, CUSEXP, CUSRSP)
Seefracht → std.edi.seafreight(BAPLIE, VERMAS, CODECO, …)
Transport → std.edi.transport (IFTMIN, IFTSTA, IFTDGN, …)
Infrastruktur → std.edi.messages (CONTRL, APERAK, GENRAL)
Kern → std.edi.core (Parser, UNA/UNB/UNZ)
Bevor eine Nachricht inhaltlich verarbeitet wird, liest man UNA (Trennzeichen) und UNB (Absender/Empfänger). Der Nachrichtentyp bestimmt, welche Unit für das eigentliche Parsing zuständig ist.
import std.edi.core;
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 inBuf: pchar := "UNA:+.? 'UNB+UNOA:1+4098765000004+4012345000009+20260813:0930+IC000042'UNH+1+ORDERS:D:01B:UN'BGM+220+BST-2026-0815+9'UNT+3+1'UNZ+1+IC000042'"c;
var buf: int64 := inBuf as int64;
var len: int64 := StrLen(inBuf);
// 1. Trennzeichen: EDI_OK = UNA vorhanden (Nutzdaten ab Byte 9),
// EDI_ERR_NOUNA = keine UNA, Standardtrennzeichen gelten (ab Byte 0)
var una: int64 := alloc(EDI_UNA_SIZE);
var start: int64 := 0;
if (EdiUnaRead(buf, len, una) == EDI_OK) { start := 9; }
// 2. Segmente durchlaufen
var sctx: int64 := alloc(EDI_SEGCTX_SIZE);
EdiSegCtxInit(sctx, una, start);
var seg: int64 := alloc(EDI_SEG_SIZE);
var elems: int64 := alloc(16 * EDI_ELEM_SIZE);
var comps: int64 := alloc(8 * EDI_ELEM_SIZE);
var ctx: int64 := alloc(EDI_CTX_SIZE);
EdiCtxInit(ctx);
while (EdiSegmentNext(buf, len, sctx, seg) == 1) {
var p: int64 := peek64(seg + EDI_SEG_PTR);
var tag: pchar := Feld(p, 3);
// 3. UNB: EdiUnbRead bekommt genau dieses eine Segment
if (StrEquals(tag, "UNB") == 1) {
EdiUnbRead(p, peek64(seg + EDI_SEG_LEN), ctx);
PrintLn(StrConcat("Absender: ", Feld(peek64(ctx + EDI_CTX_SENDER), peek64(ctx + EDI_CTX_SNDLEN))));
}
// 4. UNH: Nachrichtentyp steht in Element 1, Komponente 0
if (StrEquals(tag, "UNH") == 1) {
EdiElementSplit(seg, elems, 16);
var e1p: int64 := peek64(elems + EDI_ELEM_SIZE + EDI_ELEM_PTR);
var e1l: int64 := peek64(elems + EDI_ELEM_SIZE + EDI_ELEM_LEN);
EdiComponentSplit(e1p, e1l, comps, 8);
PrintLn(StrConcat("Nachrichtentyp: ", Feld(peek64(comps + EDI_ELEM_PTR), peek64(comps + EDI_ELEM_LEN))));
}
}
return 0;
}
Absender: 4098765000004
Nachrichtentyp: ORDERS
Der Nachrichtentyp entscheidet, welche Unit den Rumpf liest: ORDERS → EdiOrdersRead, INVOIC → EdiInvoicRead und so weiter.
Nach dem Lesen von UNH und dem Bestimmen des Nachrichtentyps die entsprechende Unit-Read-Funktion aufrufen (z. B. EdiOrdersRead, EdiInvoicRead).
Quittung senden (CONTRL):
Nach jeder empfangenen Nachricht erwartet der Sender eine CONTRL-Quittung. Ohne CONTRL weiß er nicht, ob die Nachricht ankam.
import std.edi.messages;
import std.alloc;
fn main(): int64 {
var out: int64 := alloc(2048);
// Empfang bestaetigen: icRef, eigene ID, Partner-ID
var n: int64 := EdiContrlOk("IC000042"c, "4012345000009"c,
"4098765000004"c, out, 2048);
// Bei Syntaxfehler ablehnen: icRef, Segmentposition, Fehlercode
var n2: int64 := EdiContrlErr("IC000042"c, 3, EDI_ERR_MISSING_SEG, out, 2048);
free(out, 2048);
return 0;
}
EdiContrlOk/EdiContrlErr erzeugen einen vollständigen Interchange von UNB bis UNZ — hier ist also kein eigener Umschlag nötig.
Ein vollständiger Bestellvorgang: Bestellung → Auftragsbestätigung → (Ablehnung oder Änderung).
import std.edi.orders;
import std.edi.catalog;
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 gtin: pchar := "04012345678901"c;
// GTIN vorab pruefen - keine Write-Funktion tut das
if (EdiGtinCheck(gtin, 14) == 0) {
PrintLn("Ungueltige GTIN - Bestellung abgebrochen");
return 1;
}
var hdr: int64 := alloc(EDI_ORDER_HDR_SIZE);
var i: int64 := 0;
while (i < EDI_ORDER_HDR_SIZE) { poke8(hdr + i, 0); i := i + 1; }
poke64(hdr + EDI_ORDER_HDR_NUM, "ORD-2026-4711"c as int64);
poke64(hdr + EDI_ORDER_HDR_NUMLEN, 13);
poke64(hdr + EDI_ORDER_HDR_DATE, "20260813"c as int64);
poke64(hdr + EDI_ORDER_HDR_DATELEN, 8);
poke64(hdr + EDI_ORDER_HDR_BUYER_GLN, "4012345000009"c as int64);
poke64(hdr + EDI_ORDER_HDR_BUYER_GLNL, 13);
poke64(hdr + EDI_ORDER_HDR_SUP_GLN, "4098765000004"c as int64);
poke64(hdr + EDI_ORDER_HDR_SUP_GLNL, 13);
var lines: int64 := alloc(2 * EDI_ORDER_LINE_SIZE);
i := 0;
while (i < 2 * EDI_ORDER_LINE_SIZE) { poke8(lines + i, 0); i := i + 1; }
poke64(lines + EDI_ORDER_LINE_GTIN, gtin as int64);
poke64(lines + EDI_ORDER_LINE_GTINLEN, 14);
poke64(lines + EDI_ORDER_LINE_QTY, 100);
poke64(lines + EDI_ORDER_LINE_UNIT, "PCE"c as int64);
poke64(lines + EDI_ORDER_LINE_UNITLEN, 3);
poke64(lines + EDI_ORDER_LINE_PRICE, 999); // 9,99 EUR
poke64(lines + EDI_ORDER_LINE_TAXRATE, 1900); // 19,00 %
poke64(lines + EDI_ORDER_LINE_LINENO, 1);
var l1: int64 := lines + EDI_ORDER_LINE_SIZE;
poke64(l1 + EDI_ORDER_LINE_GTIN, "04012345678918"c as int64);
poke64(l1 + EDI_ORDER_LINE_GTINLEN, 14);
poke64(l1 + EDI_ORDER_LINE_QTY, 50);
poke64(l1 + EDI_ORDER_LINE_PRICE, 2499);
poke64(l1 + EDI_ORDER_LINE_TAXRATE, 1900);
poke64(l1 + EDI_ORDER_LINE_LINENO, 2);
// Erwartete Summe im Kopf eintragen, sonst prueft Validate nichts
poke64(hdr + EDI_ORDER_HDR_TOTAL, 100 * 999 + 50 * 2499);
PrintLn(StrConcat("Summenpruefung (0 = ok): ", IntToStr(EdiOrdersValidate(hdr, lines, 2))));
var out: int64 := alloc(4096);
var n: int64 := EdiOrdersWrite(hdr, lines, 2, out, 4096);
if (n < 0) { PrintLn("Bestellnummer fehlt"); return 1; }
PrintLn(Feld(out, n));
return 0;
}
Summenpruefung (0 = ok): 0
BGM+220+ORD-2026-4711+9'DTM+137:20260813:102'NAD+BY+4012345000009::9'NAD+SU+4098765000004::9'LIN+1++04012345678901:SRV'QTY+21:100:PCE'PRI+AAA:9.99:CP'TAX+7+VAT+++:::19.00'LIN+2++04012345678918:SRV'QTY+21:50'PRI+AAA:24.99:CP'TAX+7+VAT+++:::19.00'UNS+S'MOA+77:2248.50'CNT+2:2'
Auftragsbestätigung auswerten (ORDRSP):
import std.edi.orders;
import std.alloc;
import std.string;
fn main(): int64 {
// Antwort des Lieferanten: Position 1 bestaetigt, Position 2 geaendert, Position 3 abgelehnt
var msg: pchar := "BGM+231+AB-9001+9'RFF+ON:ORD-2026-4711'LIN+1+1+04012345678901:SRV'QTY+21:100'LIN+2+5+04012345678918:SRV'QTY+21:30'LIN+3+7+04012345678925:SRV'QTY+21:0'CNT+2:3'"c;
var hdr: int64 := alloc(EDI_ORDER_HDR_SIZE);
var lines: int64 := alloc(50 * EDI_ORDER_LINE_SIZE);
var count: int64 := EdiOrdrspRead(msg as int64, StrLen(msg), hdr, lines, 50);
var i: int64 := 0;
while (i < count) {
var line: int64 := lines + i * EDI_ORDER_LINE_SIZE;
var status: int64 := peek64(line + EDI_ORDER_LINE_STATUS);
var lineno: int64 := peek64(line + EDI_ORDER_LINE_LINENO);
if (status == 1) {
PrintLn(StrConcat(StrConcat("Position ", IntToStr(lineno)), " bestaetigt"));
} else if (status == 5) {
PrintLn(StrConcat(StrConcat(StrConcat("Position ", IntToStr(lineno)), " geaendert auf Menge "),
IntToStr(peek64(line + EDI_ORDER_LINE_QTY))));
} else if (status == 7) {
PrintLn(StrConcat(StrConcat("Position ", IntToStr(lineno)), " abgelehnt"));
}
i := i + 1;
}
free(lines, 50 * EDI_ORDER_LINE_SIZE);
free(hdr, EDI_ORDER_HDR_SIZE);
return 0;
}
Position 1 bestaetigt
Position 2 geaendert auf Menge 30
Position 3 abgelehnt
Der Positionsstatus steht im zweiten Datenelement des LIN-Segments: 1 bestätigt, 5 geändert, 7 abgelehnt.
SSCC (Serial Shipping Container Code) ist eine 18-stellige GS1-Nummer, die jede Versandeinheit eindeutig identifiziert — über Unternehmensgrenzen hinweg. Das DESADV-Segment CPS (Consignment Packing Sequence) bildet die Hierarchie ab.
Was ist ein SSCC? Format: 1 Erweiterungsziffer + 7–10 stelliger GS1-Unternehmens-Präfix + fortlaufende Seriennummer + 1 Prüfziffer = 18 Stellen. Beispiel: 004000000000000011.
import std.edi.shipping;
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 {
// SSCC aus 17 Stellen erzeugen (Prüfziffer haengt die Bibliothek an)
var ssccPal: int64 := alloc(19);
var ssccKar: int64 := alloc(19);
EdiSsccGenerate("34012345000000001"c, ssccPal);
EdiSsccGenerate("34012345000000002"c, ssccKar);
// Hierarchie: Palette -> Karton -> Artikel
var pk: int64 := alloc(3 * EDI_PACKAGE_SIZE);
var i: int64 := 0;
while (i < 3 * EDI_PACKAGE_SIZE) { poke8(pk + i, 0); i := i + 1; }
var p0: int64 := pk;
poke64(p0 + EDI_PACKAGE_SSCC, ssccPal);
poke64(p0 + EDI_PACKAGE_SSCCLEN, 18);
poke64(p0 + EDI_PACKAGE_TYPE, EDI_PKG_PALLET);
poke64(p0 + EDI_PACKAGE_PARENT, 0 - 1);
var p1: int64 := pk + EDI_PACKAGE_SIZE;
poke64(p1 + EDI_PACKAGE_SSCC, ssccKar);
poke64(p1 + EDI_PACKAGE_SSCCLEN, 18);
poke64(p1 + EDI_PACKAGE_TYPE, EDI_PKG_CARTON);
poke64(p1 + EDI_PACKAGE_PARENT, 0); // haengt an Paket 0
var p2: int64 := pk + 2 * EDI_PACKAGE_SIZE;
poke64(p2 + EDI_PACKAGE_TYPE, EDI_PKG_ITEM);
poke64(p2 + EDI_PACKAGE_PARENT, 1); // liegt im Karton
poke64(p2 + EDI_PACKAGE_GTIN, "04012345678901"c as int64);
poke64(p2 + EDI_PACKAGE_GTINLEN, 14);
poke64(p2 + EDI_PACKAGE_QTY, 24);
var out: int64 := alloc(4096);
var n: int64 := EdiDesadvWrite("LS-2026-0815"c, "20260813"c, pk, 3, out, 4096);
PrintLn(Feld(out, n));
var pk2: int64 := alloc(16 * EDI_PACKAGE_SIZE);
var cnt: int64 := EdiDesadvRead(out, n, pk2, 16);
PrintLn(StrConcat("Packstuecke: ", IntToStr(cnt)));
i := 0;
while (i < cnt) {
var p: int64 := pk2 + i * EDI_PACKAGE_SIZE;
PrintLn(StrConcat(StrConcat(" Typ ", IntToStr(peek64(p + EDI_PACKAGE_TYPE))),
StrConcat(" Parent ", IntToStr(peek64(p + EDI_PACKAGE_PARENT)))));
i += 1;
}
return 0;
}
BGM+351+LS-2026-0815+9'DTM+137:20260813:102'CPS+1'PAC+1++201'PCI+33E'GIN+BJ+340123450000000017'CPS+2+1'PAC+1++CT'PCI+33E'GIN+BJ+340123450000000024'CPS+3+2'LIN+1++04012345678901:SRV'QTY+12:24'CNT+2:3'
Packstuecke: 3
Typ 1 Parent -1
Typ 2 Parent 0
Typ 3 Parent 1
Wichtig: Pakete müssen in Hierarchie-Reihenfolge übergeben werden — erst alle Paletten, dann alle Kartons, dann alle Artikel. Der PARENT-Index verweist auf den 0-basierten Positionsindex im Array.
EDIFACT unterscheidet vier Rechnungstypen über den BGM-Qualifier:
| BGM | Typ | Einsatz |
|---|---|---|
| 380 | Rechnung (Soll) | Normalfall |
| 381 | Gutschrift | Retourerstattung |
| 383 | Debit Note | Nachbelastung |
| 386 | Prepayment | Vorauszahlung |
Steuertypen (MOA-Qualifier T):
| Konstante | Typ | Satz |
|---|---|---|
EDI_INVOIC_TAX_S (1) | Normalsatz | 19 % |
EDI_INVOIC_TAX_AA (2) | Ermäßigter Satz | 7 % |
EDI_INVOIC_TAX_Z (3) | Nullsatz | 0 % |
EDI_INVOIC_TAX_E (4) | Steuerbefreit | — |
import std.edi.invoice;
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;
}
// Betrag in Cent als "123.45" ausgeben
fn Geld(cent: int64): pchar {
var r: int64 := cent - (cent / 100) * 100;
var nk: pchar := IntToStr(r);
if (r < 10) { nk := StrConcat("0", nk); }
return StrConcat(StrConcat(IntToStr(cent / 100), ","), nk);
}
fn main(): int64 {
var hdr: int64 := alloc(EDI_INVOIC_HDR_SIZE);
var i: int64 := 0;
while (i < EDI_INVOIC_HDR_SIZE) { poke8(hdr + i, 0); i := i + 1; }
poke64(hdr + EDI_INVOIC_HDR_NUM, "RE-2026-4711"c as int64);
poke64(hdr + EDI_INVOIC_HDR_NUMLEN, 12);
poke64(hdr + EDI_INVOIC_HDR_DATE, "20260813"c as int64);
poke64(hdr + EDI_INVOIC_HDR_DATELEN, 8);
poke64(hdr + EDI_INVOIC_HDR_BGMQUAL, 380); // 380 = Rechnung
poke64(hdr + EDI_INVOIC_HDR_SUPPLIER, "4098765000004"c as int64);
poke64(hdr + EDI_INVOIC_HDR_SUPLEN, 13);
poke64(hdr + EDI_INVOIC_HDR_BUYER, "4012345000009"c as int64);
poke64(hdr + EDI_INVOIC_HDR_BUYLEN, 13);
poke64(hdr + EDI_INVOIC_HDR_CURRENCY, "EUR"c as int64);
poke64(hdr + EDI_INVOIC_HDR_CURLEN, 3);
var lines: int64 := alloc(2 * EDI_INVOIC_LINE_SIZE);
i := 0;
while (i < 2 * EDI_INVOIC_LINE_SIZE) { poke8(lines + i, 0); i := i + 1; }
poke64(lines + EDI_INVOIC_LINE_GTIN, "04012345678901"c as int64);
poke64(lines + EDI_INVOIC_LINE_GTINLEN, 14);
poke64(lines + EDI_INVOIC_LINE_QTY, 24);
poke64(lines + EDI_INVOIC_LINE_PRICE, 1999);
poke64(lines + EDI_INVOIC_LINE_NETAMT, 24 * 1999);
poke64(lines + EDI_INVOIC_LINE_TAXTYPE, EDI_INVOIC_TAX_S);
poke64(lines + EDI_INVOIC_LINE_LINENO, 1);
var l1: int64 := lines + EDI_INVOIC_LINE_SIZE;
poke64(l1 + EDI_INVOIC_LINE_GTIN, "04012345678918"c as int64);
poke64(l1 + EDI_INVOIC_LINE_GTINLEN, 14);
poke64(l1 + EDI_INVOIC_LINE_QTY, 6);
poke64(l1 + EDI_INVOIC_LINE_PRICE, 4950);
poke64(l1 + EDI_INVOIC_LINE_NETAMT, 6 * 4950);
poke64(l1 + EDI_INVOIC_LINE_TAXTYPE, EDI_INVOIC_TAX_AA);
poke64(l1 + EDI_INVOIC_LINE_LINENO, 2);
var out: int64 := alloc(4096);
var n: int64 := EdiInvoicWrite(hdr, lines, 2, out, 4096);
PrintLn(Feld(out, n));
var hdr2: int64 := alloc(EDI_INVOIC_HDR_SIZE);
var lin2: int64 := alloc(8 * EDI_INVOIC_LINE_SIZE);
var cnt: int64 := EdiInvoicRead(out, n, hdr2, lin2, 8);
PrintLn(StrConcat("Positionen: ", IntToStr(cnt)));
PrintLn(StrConcat("Netto: ", Geld(peek64(hdr2 + EDI_INVOIC_HDR_NETTOTAL))));
PrintLn(StrConcat("Steuer: ", Geld(peek64(hdr2 + EDI_INVOIC_HDR_TAXTOTAL))));
PrintLn(StrConcat("Brutto: ", Geld(peek64(hdr2 + EDI_INVOIC_HDR_GROSSTOTAL))));
PrintLn(StrConcat("Validierung: ", IntToStr(EdiInvoicValidate(hdr2, lin2, cnt))));
return 0;
}
BGM+380+RE-2026-4711+9'DTM+137:20260813:102'NAD+SU+4098765000004::9'NAD+BY+4012345000009::9'CUX+2:EUR:4'LIN+1++04012345678901:SRV'QTY+47:24'PRI+AAA:19.99:CP'MOA+203:479.76'TAX+7+VAT+++:::S'LIN+2++04012345678918:SRV'QTY+47:6'PRI+AAA:49.50:CP'MOA+203:297.00'TAX+7+VAT+++:::AA'UNS+S'TAX+7+VAT+++:::S'MOA+125:479.76'MOA+124:91.15'TAX+7+VAT+++:::AA'MOA+125:297.00'MOA+124:20.79'MOA+77:776.76'MOA+176:111.94'MOA+9:888.70'CNT+2:2'
Positionen: 2
Netto: 776,76
Steuer: 111,94
Brutto: 888,70
Validierung: 0
EdiInvoicWrite rechnet Netto-, Steuer- und Bruttosumme aus den Positionen und weist die Steuer je Satz getrennt aus. EdiInvoicValidate vergleicht sie mit den Kopfwerten: 0 passt, 1 Nettodifferenz, 3 Bruttodifferenz.
std.edi.partner ist kein Netzwerktreiber, sondern ein Metadaten-Register: Wer darf welche Nachrichtentypen senden, über welchen Kanal, mit welchen Sicherheitsoptionen?
import std.edi.partner;
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 p: int64 := alloc(EDI_PART_SIZE);
var i: int64 := 0;
while (i < EDI_PART_SIZE) { poke8(p + i, 0); i := i + 1; }
poke64(p + EDI_PART_PROTOCOL, EDI_PART_PROTO_AS2);
poke64(p + EDI_PART_PARTNERID, "PARTNER-AS2-ID"c as int64);
poke64(p + EDI_PART_PARTNERLEN, 14);
poke64(p + EDI_PART_OURID, "MEINE-AS2-ID"c as int64);
poke64(p + EDI_PART_OURIDLEN, 12);
poke64(p + EDI_PART_HOST, "edi.partner.example"c as int64);
poke64(p + EDI_PART_HOSTLEN, 19);
poke64(p + EDI_PART_PORT, 443);
poke64(p + EDI_PART_PATH, "/as2/inbound"c as int64);
poke64(p + EDI_PART_PATHLEN, 12);
poke64(p + EDI_PART_MSGTYPES, EDI_PART_MSG_ORDERS + EDI_PART_MSG_INVOIC + EDI_PART_MSG_DESADV);
poke64(p + EDI_PART_OPTIONS, EDI_PART_OPT_SIGN + EDI_PART_OPT_ENCRYPT);
PrintLn(StrConcat("gueltig: ", IntToStr(EdiPartnerValidate(p))));
var out: int64 := alloc(1024);
var n: int64 := EdiPartnerWrite(p, out, 1024);
Print(Feld(out, n)); // Zeile endet bereits mit \n
// Zeile wieder einlesen
var p2: int64 := alloc(EDI_PART_SIZE);
if (EdiPartnerRead(out, n, p2) == 1) {
PrintLn(StrConcat("Host: ", Feld(peek64(p2 + EDI_PART_HOST), peek64(p2 + EDI_PART_HOSTLEN))));
PrintLn(StrConcat("Port: ", IntToStr(peek64(p2 + EDI_PART_PORT))));
PrintLn(StrConcat("ORDERS erlaubt: ", IntToStr(EdiPartnerSupports(p2, EDI_PART_MSG_ORDERS))));
PrintLn(StrConcat("CUSTOMS erlaubt: ", IntToStr(EdiPartnerSupports(p2, EDI_PART_MSG_CUSTOMS))));
}
// Registry: mehrere Zeilen, Suche nach Partner-ID
var parts: int64 := alloc(4 * EDI_PART_SIZE);
var cnt: int64 := EdiPartnerListRead(out, n, parts, 4);
// EdiPartnerFind liefert einen ZEIGER auf den Datensatz, keinen Index - 0 = nicht gefunden
var rec: int64 := EdiPartnerFind(parts, cnt, "PARTNER-AS2-ID"c, 14);
if (rec != 0) {
PrintLn(StrConcat("Registry-Eintraege: ", IntToStr(cnt)));
PrintLn(StrConcat("Pfad des Treffers: ", Feld(peek64(rec + EDI_PART_PATH), peek64(rec + EDI_PART_PATHLEN))));
} else {
PrintLn("Partner nicht gefunden");
}
return 0;
}
gueltig: 1
AS2|PARTNER-AS2-ID|MEINE-AS2-ID|edi.partner.example|443|/as2/inbound|ORDERS,INVOIC,DESADV|3
Host: edi.partner.example
Port: 443
ORDERS erlaubt: 1
CUSTOMS erlaubt: 0
Registry-Eintraege: 1
Pfad des Treffers: /as2/inbound
Eine Partner-Registry ist damit eine einfache Textdatei — eine pipe-getrennte Zeile je Partner, die EdiPartnerListRead wieder einliest. EdiPartnerFind liefert einen Zeiger auf den Treffer (0 = nicht gefunden), keinen Index.
Vor dem Senden eines Zahlungsavis (REMADV) oder Lastschriftauftrags (DIRDEB) immer IBAN und BIC prüfen.
import std.edi.payment;
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_PAY_HDR_SIZE);
var i: int64 := 0;
while (i < EDI_PAY_HDR_SIZE) { poke8(hdr + i, 0); i := i + 1; }
poke64(hdr + EDI_PAY_HDR_REF, "AVIS-2026-0091"c as int64);
poke64(hdr + EDI_PAY_HDR_REFLEN, 14);
poke64(hdr + EDI_PAY_HDR_DATE, "20260813"c as int64);
poke64(hdr + EDI_PAY_HDR_DATELEN, 8);
poke64(hdr + EDI_PAY_HDR_AMOUNT, 88870); // 888,70 EUR
poke64(hdr + EDI_PAY_HDR_CURRENCY, "EUR"c as int64);
poke64(hdr + EDI_PAY_HDR_CURLEN, 3);
poke64(hdr + EDI_PAY_HDR_CREDIBAN, "DE89370400440532013000"c as int64);
poke64(hdr + EDI_PAY_HDR_CREDILEN, 22);
poke64(hdr + EDI_PAY_HDR_BIC, "COBADEFFXXX"c as int64);
poke64(hdr + EDI_PAY_HDR_BICLEN, 11);
poke64(hdr + EDI_PAY_HDR_INVOICEREF, "RE-2026-4711"c as int64);
poke64(hdr + EDI_PAY_HDR_INVOICELEN, 12);
// Bankdaten selbst pruefen - die Write-Funktionen tun es nicht
PrintLn(StrConcat("IBAN gueltig: ", IntToStr(EdiIbanCheck(peek64(hdr + EDI_PAY_HDR_CREDIBAN), 22))));
PrintLn(StrConcat("BIC gueltig: ", IntToStr(EdiBicCheck(peek64(hdr + EDI_PAY_HDR_BIC), 11))));
PrintLn(StrConcat("REMADV-Pflichtfelder (0 = ok): ", IntToStr(EdiRemadvCheck(hdr))));
var out: int64 := alloc(4096);
var n: int64 := EdiRemadvWrite(hdr, out, 4096);
PrintLn(Feld(out, n));
var hdr2: int64 := alloc(EDI_PAY_HDR_SIZE);
EdiRemadvRead(out, n, hdr2);
PrintLn(StrConcat("Betrag/100: ", IntToStr(peek64(hdr2 + EDI_PAY_HDR_AMOUNT))));
return 0;
}
IBAN gueltig: 1
BIC gueltig: 1
REMADV-Pflichtfelder (0 = ok): 0
BGM+481+AVIS-2026-0091+9'DTM+137:20260813:102'FII+CR+DE89370400440532013000:COBADEFFXXX:25'CUX+2:EUR:4'MOA+9:888.70'RFF+IV:RE-2026-4711'CNT+2:1'
Betrag/100: 88870
Unterschied DIRDEB vs. REMADV:
| REMADV (481) | Avis: „Ich habe bereits gezahlt“ — Bezug auf Rechnung (RFF+IV) |
| DIRDEB (431) | Einzug: „Ich werde abbuchen“ — Mandatsreferenz Pflicht (RFF+MR) |
DELFOR ist der rollierender Lieferplan: Jeden Montag schickt der Käufer dem Lieferanten eine aktualisierte Übersicht über die nächsten 4–52 Wochen. Typ 1 = fester Bedarf (Produktion garantiert), Typ 3 = Planungsbedarf (Prognose, kann sich noch ändern).
import std.edi.delfor;
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 {
// DELFOR: eine Materialnummer, drei Abrufe (1x fest, 2x Vorschau)
var lines: int64 := alloc(EDI_DELFOR_LINE_SIZE);
var i: int64 := 0;
while (i < EDI_DELFOR_LINE_SIZE) { poke8(lines + i, 0); i := i + 1; }
poke64(lines + EDI_DELFOR_LINE_GTIN, "04012345678901"c as int64);
poke64(lines + EDI_DELFOR_LINE_GTINLEN, 14);
poke64(lines + EDI_DELFOR_LINE_CUMULQTY, 12000); // Fortschrittszahl
poke64(lines + EDI_DELFOR_LINE_REQCOUNT, 3);
var req: int64 := lines + EDI_DELFOR_LINE_REQS;
poke64(req + EDI_DELFOR_REQ_DATE, "20260817"c as int64);
poke64(req + EDI_DELFOR_REQ_QTY, 600);
poke64(req + EDI_DELFOR_REQ_TYPE, 1); // 1 = fester Abruf
var r1: int64 := req + EDI_DELFOR_REQ_SIZE;
poke64(r1 + EDI_DELFOR_REQ_DATE, "20260824"c as int64);
poke64(r1 + EDI_DELFOR_REQ_QTY, 600);
poke64(r1 + EDI_DELFOR_REQ_TYPE, 3); // 3 = Planzahl
var r2: int64 := req + 2 * EDI_DELFOR_REQ_SIZE;
poke64(r2 + EDI_DELFOR_REQ_DATE, "20260831"c as int64);
poke64(r2 + EDI_DELFOR_REQ_QTY, 450);
poke64(r2 + EDI_DELFOR_REQ_TYPE, 3);
var out: int64 := alloc(8192);
var n: int64 := EdiDelforWrite("ABR-2026-33"c, "20260813"c, lines, 1, out, 8192);
PrintLn(Feld(out, n));
var l2: int64 := alloc(2 * EDI_DELFOR_LINE_SIZE);
var cnt: int64 := EdiDelforRead(out, n, l2, 2);
PrintLn(StrConcat(StrConcat("Zeilen: ", IntToStr(cnt)),
StrConcat(" Abrufe: ", IntToStr(peek64(l2 + EDI_DELFOR_LINE_REQCOUNT)))));
// Fortschrittszahl darf nie sinken
PrintLn(StrConcat("Kumulativ 12600 nach 12000 ok: ", IntToStr(EdiDelforCheckCumu(12600, 12000))));
PrintLn(StrConcat("Kumulativ 11000 nach 12000 ok: ", IntToStr(EdiDelforCheckCumu(11000, 12000))));
return 0;
}
BGM+241+ABR-2026-33+9'DTM+137:20260813:102'LIN+1++04012345678901:SRV'SCC+1+12000'QTY+1:600'DTM+64:20260817:102'QTY+3:600'DTM+64:20260824:102'QTY+3:450'DTM+64:20260831:102'CNT+2:1'
Zeilen: 1 Abrufe: 3
Kumulativ 12600 nach 12000 ok: 0
Kumulativ 11000 nach 12000 ok: 1
Speicherhinweis: EDI_DELFOR_LINE_SIZE = 1 280 Bytes pro Artikel (Kopf 32 B + 52 × 24 B für Anforderungen). Bei 100 Artikeln sind das 128 KB. Bei sehr vielen Artikeln Puffer-Größe sorgfältig wählen.
Die GS1-Identifikationsnummern sind das Rückgrat des EDIFACT-Handels. Lyx validiert alle gängigen Formate:
| Funktion | Typ | Länge | Algorithmus |
|---|---|---|---|
EdiGtinCheck | GTIN (EAN) | 8, 12, 13, 14 | GS1 Mod-10 |
EdiGlnCheck | GLN (Firmenstandort) | 13 | GS1 Mod-10 |
EdiSsccCheck | SSCC-18 | 18 | GS1 Mod-10 |
EdiContainerCheck | ISO 6346 Container | 11 | Zweierpotenzen Mod-11, Rest %10 |
EdiIbanCheck | IBAN | variabel | MOD-97 |
EdiBicCheck | BIC/SWIFT | 8 oder 11 | Strukturell |
EdiUnNumberCheck | UN-Gefahrgutnummer | 4 | Genau 4 Ziffern |
GS1 Mod-10-Algorithmus (für GTIN, GLN, SSCC):
import std.edi.catalog;
import std.edi.shipping;
import std.alloc;
import std.string;
fn main(): int64 {
// Alle GS1-Nummern vor Verwendung pruefen (1 = gueltig)
PrintLn(StrConcat("GTIN: ", IntToStr(EdiGtinCheck("04012345678901"c, 14))));
PrintLn(StrConcat("GLN: ", IntToStr(EdiGlnCheck("4012345000009"c, 13))));
// Eine SSCC baut man am besten aus 17 Stellen - die Pruefziffer rechnet die Unit
var sscc: int64 := alloc(19);
EdiSsccGenerate("34012345000000001"c, sscc);
PrintLn(StrConcat(StrConcat("SSCC: ", sscc as pchar), StrConcat(" -> ", IntToStr(EdiSsccCheck(sscc as pchar, 18)))));
// Von Hand erfundene Pruefziffern fallen durch
PrintLn(StrConcat("SSCC 004000000000000011: ", IntToStr(EdiSsccCheck("004000000000000011"c, 18))));
return 0;
}
GTIN: 1
GLN: 1
SSCC: 340123450000000017 -> 1
SSCC 004000000000000011: 0
Die zuletzt geprüfte Nummer stammt aus einer älteren Fassung dieser Seite — sie sieht plausibel aus, trägt aber die falsche Prüfziffer. Genau dafür gibt es EdiSsccGenerate.
Beschaffungsprozess (Retail/Industrie):
Käufer (Retailer) Lieferant
REQOTE → Preisanfrage
← QUOTES Angebot
ORDERS → Bestellung
← ORDRSP Bestätigung (oder Ablehnung)
← DESADV Lieferschein (vor Versand)
Wareneingang:
RECADV → Wareneingangsbestätigung
← INVOIC Rechnung
REMADV → Zahlungsavis
← CONTRL Quittung jeder Nachricht
Automobilzulieferung (Just-in-Time):
OEM Zulieferer
DELFOR → Wochenlieferplan (jeden Montag)
DELJIT → JIT-Abruf (Stunden vorher, exakte Zeit)
← DESADV Lieferschein (SSCC pro Behälter)
← INVOIC Rechnung (oft monatliche Sammelrechnung)
COMDIS → Rechnungsdisput (bei Differenzen)
← COACSU Saldenabstimmung
Seefracht (Container-Logistik):
Verlader/Spediteur Terminalbetreiber / Reederei
CUSCAR → Zollanmeldung Carrier
CUSDEC → Zollanmeldung Anmelder
← CUSRSP Zollantwort (akzeptiert/freigegeben)
COPARN → Voranmeldung Container-Einlauf
← CODECO Gate-In-Bestätigung
VERMAS → VGM-Gewicht (SOLAS-Pflicht!)
← BAPLIE Stauplan
← COARRI Ankunftsmeldung
← COPINO Pick-up-Freigabe
CONTRL ist die universelle Quittung für alle EDIFACT-Nachrichten. Ohne CONTRL weiß der Sender nicht, ob die Nachricht ankam und korrekt verarbeitet wurde.
| Status | Bedeutung |
|---|---|
| ACCEPTED (7) | Nachricht wurde akzeptiert und verarbeitet |
| REJECTED4 (4) | Abgelehnt auf Interchange-Ebene (UNB-Fehler) |
| REJECTED5 (5) | Abgelehnt auf Nachrichten-Ebene (Inhaltsfehler) |
| Fehlercode | Bedeutung |
|---|---|
EDI_ERR_SYNTAX (3) | Syntaxfehler (falsche Segmentfolge, fehlende Pflichtfelder) |
EDI_ERR_NOUNA (2) | Keine UNA — Trennzeichen unklar |
EDI_ERR_TRUNC (1) | Nachricht unvollständig (Übertragungsabbruch) |
EDI_ERR_DUP (4) | Doppelt empfangene Nachricht (gleiche UNB-Referenz) |
EDI_ERR_OVERFLOW (5) | Puffer zu klein |
EDI_ERR_PARTNER (6) | Unbekannter Absender (nicht in Partnerliste) |
APERAK (Application Error and Acknowledgement) ist die inhaltliche Fehlermeldung. Während CONTRL Syntaxprobleme meldet, erklärt APERAK fachliche Probleme („GTIN unbekannt“, „GLN nicht registriert“).
import std.edi.messages;
import std.alloc;
fn main(): int64 {
var out: int64 := alloc(2048);
// Syntaxfehler per CONTRL melden: icRef, Segmentposition, Fehlercode
EdiContrlErr("IC000042"c, 3, EDI_ERR_SYNTAX, out, 2048);
// Fachlichen Fehler per APERAK melden: Bezugsnachricht, Fehlercode, Freitext
EdiAperakWrite("BST-2026-0815"c, 14,
"GTIN 04012345678900 unbekannt"c, out, 2048);
free(out, 2048);
return 0;
}
std.edi.core führt je Partner einen Ringpuffer mit 128 Interchange-Referenzen (maximal 16 Partner je EdiState). Geprüft wird nicht automatisch: EdiDuplicateCheck muss nach dem Lesen des UNB selbst aufgerufen werden. Der Rückgabewert ist 1 für ein Duplikat und 0 für eine neue Referenz — die dabei gleich registriert wird. Doppelt empfangene Nachrichten sind im EDI-Alltag nicht selten (Timeouts, Retry-Loops auf AS2-Ebene).
import std.edi.core;
import std.alloc;
import std.string;
fn main(): int64 {
var state: int64 := alloc(EDI_STATE_SIZE);
EdiStateInit(state);
var partner: pchar := "4098765000004"c; // Partnerschluessel (z. B. Absender-GLN)
var icRef: pchar := "IC000042"c; // Interchange-Referenz aus dem UNB
// Erster Empfang: 0 = neu, wird registriert
PrintLn(StrConcat("1. Empfang: ", IntToStr(EdiDuplicateCheck(state, partner as int64, icRef as int64))));
// Zweiter Empfang derselben Referenz: 1 = Duplikat
PrintLn(StrConcat("2. Empfang: ", IntToStr(EdiDuplicateCheck(state, partner as int64, icRef as int64))));
// Laufende Nummer fuer ausgehende Interchanges je Partner
PrintLn(StrConcat("naechste Sequenznummer: ", IntToStr(EdiSeqNext(state, partner))));
free(state, EDI_STATE_SIZE);
return 0;
}
1. Empfang: 0
2. Empfang: 1
naechste Sequenznummer: 1
Der Ring überschreibt nach 128 Referenzen die ältesten Einträge, und der Zustand lebt nur im Speicher. Für eine Duplikatssperre über Stunden oder Neustarts hinweg gehört zusätzlich eine persistente Tabelle in die Anwendung.
int64 × 100. 1999 = 19,99 €. Niemals f64 für Geldrechnung — Rundungsfehler!EDI_INVOIC_HDR_NETTOTAL, …_TAXTOTAL und …_GROSSTOTAL werden beim Schreiben aus den Positionen neu berechnet. Den Positionsbetrag EDI_INVOIC_LINE_NETAMT rechnet die Bibliothek dagegen nicht aus — er muss gesetzt sein, sonst steht die Rechnung auf 0,00 €.EDI_ORDER_HDR_NUM nicht gesetzt. Immer prüfen.rfqRef ist Pflichtfeld — ohne Bezug auf die ursprüngliche REQOTE gibt EdiQuotesWrite -1 zurück.EdiOrdersValidate, EdiInvoicValidate, EdiRemadvCheck, EdiDirdebCheck, EdiPaymulValidate, EdiDelforCheckCumu, EdiIftstaStatusCheck und EdiIftfccCheck liefern 0, wenn alles stimmt. Die GS1-/Bank-Validatoren (EdiGtinCheck, EdiIbanCheck, …) machen es umgekehrt: 1 = gültig.std.edi.core: Die Fachunits schreiben nur den Nachrichtenrumpf (BGM, DTM, LIN …). UNA/UNB/UNH davor und UNT/UNZ dahinter erzeugt der Aufrufer — Ausnahme ist CONTRL, das einen vollständigen Interchange liefert.msgRef, msgType und grpRef in EdiUnhWrite/EdiUntWrite/EdiUngWrite sowie orderRef/confirmNum bei ORDRSP sind Zeiger auf nullterminierten Text, obwohl sie als int64 deklariert sind. Eine echte Zahl wird als Adresse gelesen und stürzt ab.EdiOrdersRead und Verwandte nullen dagegen ihre Kopf-Structs selbst.EdiDirdebCheck gibt Fehlercode 2 zurück. SEPA-Lastschriften ohne Mandatsreferenz sind rechtlich ungültig.EdiGenralRead alloziert den Body-Puffer — die einzige Stelle in std.edi, an der die Bibliothek selbst Speicher anfordert. Danach free(peek64(result + EDI_GENRAL_BODY), peek64(result + EDI_GENRAL_BODYLEN)) aufrufen.std.edi.partner implementiert keinen AS2-Transport. Die Optionen (SIGN, ENCRYPT, MDN_SYNC) werden von der übergeordneten Kommunikationsschicht ausgelesen und angewendet.EdiContainerCheck implementiert das korrekt.EDI_DELFOR_LINE_SIZE = 1 280 Bytes. Bei 100 Positionen → 128 KB. Vor der Allokation mit alloc() Größe berechnen.Welchen Nachrichtentyp für welchen Zweck?
| Aufgabe | Nachricht | Unit |
|---|---|---|
| Preisanfrage stellen | REQOTE | std.edi.rfq |
| Angebot zurückmelden | QUOTES | std.edi.rfq |
| Bestellung aufgeben | ORDERS | std.edi.orders |
| Bestellung bestätigen/ablehnen | ORDRSP | std.edi.orders |
| Bestellung ändern | ORDCHG | std.edi.orders |
| Lieferschein senden | DESADV | std.edi.shipping |
| Wareneingang bestätigen | RECADV | std.edi.shipping |
| Rechnung stellen | INVOIC (BGM 380) | std.edi.invoice |
| Gutschrift stellen | INVOIC (BGM 381) | std.edi.invoice |
| Rechnungsdisput eröffnen | COMDIS | std.edi.invoice |
| Saldenabstimmung | COACSU | std.edi.invoice |
| Zahlung ankündigen | REMADV | std.edi.payment |
| Einzelzahlung beauftragen | PAYORD | std.edi.payment |
| Sammelüberweisung | PAYMUL | std.edi.payment |
| Lastschrift einziehen | DIRDEB | std.edi.payment |
| Zahlungsstornierung | FINCAN | std.edi.payment |
| Akkreditiv eröffnen | DOCAPP | std.edi.payment |
| Lagerbestand melden | INVRPT | std.edi.inventory |
| Absatzdaten melden | SLSRPT | std.edi.inventory |
| Absatzprognose melden | SLSFCT | std.edi.inventory |
| Wochenlieferplan | DELFOR | std.edi.delfor |
| JIT-Minuten-Abruf | DELJIT | std.edi.delfor |
| Zollanmeldung | CUSDEC | std.edi.customs |
| Zollantwort lesen | CUSRSP | std.edi.customs |
| Containerstauplan | BAPLIE | std.edi.seafreight |
| VGM-Gewicht melden (SOLAS) | VERMAS | std.edi.seafreight |
| Transportauftrag | IFTMIN | std.edi.transport |
| Sendungsstatus abfragen | IFTSTA | std.edi.transport |
| Gefahrgutmeldung | IFTDGN | std.edi.transport |
| Empfangsquittung | CONTRL | std.edi.messages |
| Fachliche Fehlermeldung | APERAK | std.edi.messages |
Weiterführend: std.edi — Übersicht aller Units · std.edi.core · std.net
Letzte Aktualisierung: 2026-08-13 — sämtliche zwölf Codebeispiele durch lauffähige Programme ersetzt, übersetzt und ausgeführt (lyxc 1.0.21A), echte Ausgaben ergänzt. Dabei berichtigt: falsche Aufrufsignaturen (EdiUnaRead, EdiUnbRead, EdiSegCtxInit, EdiSegmentNext, EdiContrlOk/Err, EdiAperakWrite, EdiDuplicateCheck), erfundene Konstantennamen (EDI_TAX_*, EDI_MSGTYPE_*, EDI_PROTO_AS2, EDI_AS2_*, EDI_PART_OURLEN, EDI_INVOIC_HDR_ORDERREF, …_BUYER_LEN), die Ringpuffergröße der Duplikatserkennung (128 je Partner, nicht 256 gesamt) und EdiPartnerFind (liefert einen Zeiger, keinen Index).
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).