====== std.edi.orders ======
Bestellprozess per EDIFACT: Bestellung, Auftragsbestätigung und Änderungsauftrag. Alle vier NAD-Rollen (Käufer, Lieferant, Lieferadresse, Rechnungsempfänger) werden beim Lesen automatisch extrahiert.
* **ORDERS** (BGM 220) — Bestellung (Purchase Order)
* **ORDRSP** (BGM 231) — Auftragsbestätigung mit positionsgenauen Status-Codes
* **ORDCHG** (BGM 230) — Änderungsauftrag mit laufender Änderungsnummer
import std.edi.orders;
import std.alloc;
import std.string;
// Zero-Copy-Felder sind nicht nullterminiert - terminierte Kopie fuer die Ausgabe.
fn Feld(ptr: int64, len: int64): pchar {
var b: int64 := alloc(len + 1);
var i: int64 := 0;
while (i < len) { poke8(b + i, peek8(ptr + i)); i := i + 1; }
poke8(b + len, 0);
return b as pchar;
}
fn main(): int64 {
// Kopf - Structs immer selbst nullen
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, "BST-2026-0815"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);
// Zwei Positionen
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; }
var l0: int64 := lines;
poke64(l0 + EDI_ORDER_LINE_GTIN, "04012345678901"c as int64);
poke64(l0 + EDI_ORDER_LINE_GTINLEN, 14);
poke64(l0 + EDI_ORDER_LINE_QTY, 24);
poke64(l0 + EDI_ORDER_LINE_PRICE, 1999); // 19,99 EUR
poke64(l0 + 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, 6);
poke64(l1 + EDI_ORDER_LINE_PRICE, 4950); // 49,50 EUR
poke64(l1 + EDI_ORDER_LINE_LINENO, 2);
if (EdiOrdersValidate(hdr, lines, 2) != EDI_OK) { PrintLn("ungueltig"); return 1; }
var out: int64 := alloc(4096);
var n: int64 := EdiOrdersWrite(hdr, lines, 2, out, 4096);
PrintLn(Feld(out, n));
// Und wieder zurueck
var hdr2: int64 := alloc(EDI_ORDER_HDR_SIZE);
var lin2: int64 := alloc(8 * EDI_ORDER_LINE_SIZE);
var cnt: int64 := EdiOrdersRead(out, n, hdr2, lin2, 8);
PrintLn(StrConcat("Positionen: ", IntToStr(cnt)));
PrintLn(StrConcat("Bestellnr: ", Feld(peek64(hdr2 + EDI_ORDER_HDR_NUM), peek64(hdr2 + EDI_ORDER_HDR_NUMLEN))));
PrintLn(StrConcat("Summe/100: ", IntToStr(peek64(hdr2 + EDI_ORDER_HDR_TOTAL))));
return 0;
}
BGM+220+BST-2026-0815+9'DTM+137:20260813:102'NAD+BY+4012345000009::9'NAD+SU+4098765000004::9'LIN+1++04012345678901:SRV'QTY+21:24'PRI+AAA:19.99:CP'LIN+2++04012345678918:SRV'QTY+21:6'PRI+AAA:49.50:CP'UNS+S'MOA+77:776.76'CNT+2:2'
Positionen: 2
Bestellnr: BST-2026-0815
Summe/100: 77676
''EdiOrdersWrite'' erzeugt nur den Nachrichtenrumpf. Umschlag (UNA/UNB/UNH … UNT/UNZ) kommt aus [[lyx_-_programmiersprache:units:edi:core|std.edi.core]]. Den Gesamtbetrag (''MOA+77'') rechnet die Funktion selbst aus den Positionen aus — ihn im Kopf zu setzen ist nur für ''EdiOrdersValidate'' nötig.
----
===== Imports =====
* ''std.edi.core''
* ''std.alloc''
----
===== Structs =====
==== EdiOrderLine (EDI_ORDER_LINE_SIZE = 80 Bytes) ====
^ Offset-Konstante ^ Inhalt ^
| ''EDI_ORDER_LINE_GTIN / EDI_ORDER_LINE_GTINLEN'' | GTIN-Zeiger und -Länge |
| ''EDI_ORDER_LINE_QTY'' | Bestellmenge |
| ''EDI_ORDER_LINE_UNIT / EDI_ORDER_LINE_UNITLEN'' | Mengeneinheit (optional) |
| ''EDI_ORDER_LINE_PRICE'' | Einzelpreis × 100 (Festkomma) |
| ''EDI_ORDER_LINE_TAXRATE'' | Steuersatz × 100 (z. B. 1900 = 19,00 %) |
| ''EDI_ORDER_LINE_DATE'' | Zeiger auf Lieferdatum "YYYYMMDD" (0 = kein Wunschtermin) |
| ''EDI_ORDER_LINE_STATUS'' | Position-Status: 0=normal, 1=bestätigt, 5=geändert, 7=abgelehnt |
| ''EDI_ORDER_LINE_LINENO'' | Zeilennummer (1-basiert) |
==== EdiOrderHdr (EDI_ORDER_HDR_SIZE = 112 Bytes) ====
^ Offset-Konstante ^ Inhalt ^
| ''EDI_ORDER_HDR_NUM / EDI_ORDER_HDR_NUMLEN'' | Bestellnummer |
| ''EDI_ORDER_HDR_DATE / EDI_ORDER_HDR_DATELEN'' | Bestelldatum |
| ''EDI_ORDER_HDR_BUYER_GLN / EDI_ORDER_HDR_BUYER_GLNL'' | GLN Käufer (NAD+BY) |
| ''EDI_ORDER_HDR_SUP_GLN / EDI_ORDER_HDR_SUP_GLNL'' | GLN Lieferant (NAD+SU) |
| ''EDI_ORDER_HDR_DELIV_GLN / EDI_ORDER_HDR_DELIV_GLNL'' | GLN Lieferadresse (NAD+DP) |
| ''EDI_ORDER_HDR_INV_GLN / EDI_ORDER_HDR_INV_GLNL'' | GLN Rechnungsempfänger (NAD+IV) |
| ''EDI_ORDER_HDR_TOTAL'' | Gesamtbetrag × 100 (MOA+77) |
| ''EDI_ORDER_HDR_CHANGENO'' | Änderungsnummer (ORDCHG: muss pro Änderung erhöht werden) |
----
===== Funktionen =====
==== ORDERS ====
^ Signatur ^ Beschreibung ^
| ''EdiOrdersWrite(hdr: int64, lines: int64, lineCount: int64, out: int64, outMax: int64): int64'' | Schreibt ORDERS. Gibt ''-1'' wenn Bestellnummer fehlt. |
| ''EdiOrdersRead(buf: int64, bufLen: int64, hdr: int64, lines: int64, maxLines: int64): int64'' | Parst ORDERS; befüllt ''hdr'' und ''lines''. Gibt Zeilenanzahl zurück. Alle 4 NAD-Rollen werden extrahiert. |
| ''EdiOrdersValidate(hdr: int64, lines: int64, lineCount: int64): int64'' | Vergleicht die Summe aller Positionen (''qty × price'', in Cent) mit ''EDI_ORDER_HDR_TOTAL''. Toleranz 1 Cent. ''0'' (= ''EDI_OK'') bei Übereinstimmung, ''1'' bei Abweichung. **Ist ''TOTAL'' 0, gibt die Funktion ohne Prüfung ''0'' zurück.** |
==== ORDRSP — Auftragsbestätigung ====
^ Signatur ^ Beschreibung ^
| ''EdiOrdrspWrite(orderRef: int64, confirmNum: int64, lines: int64, lineCount: int64, out: int64, outMax: int64): int64'' | Schreibt ORDRSP mit Positionsstatus (STATUS-Feld der Zeilen: 1=bestätigt, 5=geändert, 7=abgelehnt) |
| ''EdiOrdrspRead(buf: int64, bufLen: int64, hdr: int64, lines: int64, maxLines: int64): int64'' | Parst ORDRSP; gibt Zeilenanzahl zurück |
==== ORDCHG — Änderungsauftrag ====
^ Signatur ^ Beschreibung ^
| ''EdiOrdchgWrite(orderRef: int64, changeNo: int64, lines: int64, lineCount: int64, out: int64, outMax: int64): int64'' | Schreibt ORDCHG. ''changeNo'' muss mit jeder Änderung erhöht werden (EDIFACT-Pflicht). |
| ''EdiOrdchgRead(buf: int64, bufLen: int64, hdr: int64, lines: int64, maxLines: int64): int64'' | Parst ORDCHG; befüllt ''hdr.EDI_ORDER_HDR_CHANGENO'' |
----
===== Codebeispiel — Auftragsbestätigung schreiben und auswerten =====
import std.edi.orders;
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 lines: int64 := alloc(2 * EDI_ORDER_LINE_SIZE);
var i: int64 := 0;
while (i < 2 * EDI_ORDER_LINE_SIZE) { poke8(lines + i, 0); i := i + 1; }
// Position 1 bestaetigt, Position 2 abgelehnt
poke64(lines + EDI_ORDER_LINE_GTIN, "04012345678901"c as int64);
poke64(lines + EDI_ORDER_LINE_GTINLEN, 14);
poke64(lines + EDI_ORDER_LINE_QTY, 24);
poke64(lines + EDI_ORDER_LINE_LINENO, 1);
poke64(lines + EDI_ORDER_LINE_STATUS, 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, 0);
poke64(l1 + EDI_ORDER_LINE_LINENO, 2);
poke64(l1 + EDI_ORDER_LINE_STATUS, 7);
// orderRef und confirmNum sind nullterminierte Strings, keine Zahlen
var out: int64 := alloc(4096);
var n: int64 := EdiOrdrspWrite("BST-2026-0815"c, "AB-9001"c, lines, 2, out, 4096);
PrintLn(Feld(out, n));
var hdr2: int64 := alloc(EDI_ORDER_HDR_SIZE);
var lin2: int64 := alloc(8 * EDI_ORDER_LINE_SIZE);
var cnt: int64 := EdiOrdrspRead(out, n, hdr2, lin2, 8);
i := 0;
while (i < cnt) {
var l: int64 := lin2 + i * EDI_ORDER_LINE_SIZE;
var st: int64 := peek64(l + EDI_ORDER_LINE_STATUS);
if (st == 1) { PrintLn(StrConcat("bestaetigt: Position ", IntToStr(peek64(l + EDI_ORDER_LINE_LINENO)))); }
if (st == 7) { PrintLn(StrConcat("abgelehnt: Position ", IntToStr(peek64(l + EDI_ORDER_LINE_LINENO)))); }
i += 1;
}
return 0;
}
BGM+231+AB-9001+9'RFF+ON:BST-2026-0815'LIN+1+1+04012345678901:SRV'QTY+21:24'LIN+2+7+04012345678918:SRV'QTY+21:0'CNT+2:2'
bestaetigt: Position 1
abgelehnt: Position 2
----
===== Hinweise =====
* **Änderungsnummer ORDCHG**: ''EDI_ORDER_HDR_CHANGENO'' muss mit jeder neuen ORDCHG inkrementiert werden. Die Gegenseite erkennt damit, ob sie die aktuellste Änderung sieht.
* **NAD-Rollen**: ''EdiOrdersRead'' extrahiert alle vier Rollen. Nicht vorhandene Rollen haben Zeiger 0 und Länge 0.
* **Gesamtbetrag-Validierung**: ''EdiOrdersValidate'' erlaubt 1 Cent Rundungsabweichung. Ohne gesetzten ''EDI_ORDER_HDR_TOTAL'' prüft sie nichts — wer validieren will, muss den erwarteten Betrag vorher eintragen.
* **Der Kopf-Gesamtbetrag wird beim Schreiben überschrieben**: ''EdiOrdersWrite'' rechnet ''MOA+77'' selbst aus den Positionen aus.
* **Strings statt Zahlen bei ORDRSP/ORDCHG**: ''orderRef'' und ''confirmNum'' sind Zeiger auf nullterminierten Text (''%%"AB-9001"c as int64%%''); nur ''changeNo'' bei ''EdiOrdchgWrite'' ist eine echte Zahl.
* **Structs selbst nullen.** ''EdiOrdersWrite'' liest jedes Feld; nicht initialisierter Speicher erzeugt Zufallszeiger. ''EdiOrdersRead'' nullt den Kopf dagegen selbst.
* **Preise und Beträge sind ×100** — ''77676'' bedeutet 776,76 €.
----
===== Quelldatei =====
^ Unit ^ Datei ^
| ''std.edi.orders'' | ''std/edi/orders.lyx'' |
Letzte Aktualisierung: 2026-08-13 — beide Beispiele lauffähig gemacht, ausgeführt und um die echten Ausgaben ergänzt (lyxc 1.0.17K); Semantik von ''EdiOrdersValidate'' (TOTAL = 0 prüft nichts) und die Zeiger-Parameter von ORDRSP/ORDCHG klargestellt
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).