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