====== std.edi.catalog ====== Stammdaten-Austausch per EDIFACT: Artikelkataloge mit Preisen und Gültigkeitszeiträumen (PRICAT) sowie Partnerdaten mit GLN-Adressen (PARTIN). GS1-Validierungsfunktionen für GTIN und GLN sind in dieser Unit enthalten. * **PRICAT** — Price/Sales Catalogue: GTINs, Brutto-/Nettopreise, Mengeneinheiten, Gültigkeitszeiträume * **PARTIN** — Party Information: GLN-basierte Adressen und Kontaktdaten GS1-Validierungen: ^ Funktion ^ Unterstützte Längen ^ Algorithmus ^ | ''EdiGtinCheck'' | 8, 12, 13, 14 Stellen | GS1 Mod-10 (Prüfziffer) | | ''EdiGlnCheck'' | 13 Stellen | GS1 Mod-10 | **Achtung**: ''EdiPricatWrite'' validiert GTINs **nicht** — das liegt in der Verantwortung des Callers. 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 items: int64 := alloc(2 * EDI_PRICAT_ITEM_SIZE); var i: int64 := 0; while (i < 2 * EDI_PRICAT_ITEM_SIZE) { poke8(items + i, 0); i := i + 1; } var a: int64 := items; poke64(a + EDI_PRICAT_GTIN, "04012345678901"c as int64); poke64(a + EDI_PRICAT_GTINLEN, 14); poke64(a + EDI_PRICAT_DESC, "Kaffee gemahlen 500g"c as int64); poke64(a + EDI_PRICAT_DESCLEN, 20); poke64(a + EDI_PRICAT_GROSSPRICE, 1999); poke64(a + EDI_PRICAT_NETPRICE, 1799); poke64(a + EDI_PRICAT_CURRENCY, "EUR"c as int64); poke64(a + EDI_PRICAT_CURRENCYLEN, 3); poke64(a + EDI_PRICAT_VALIDFROM, "20260901"c as int64); poke64(a + EDI_PRICAT_VALIDTO, "20261231"c as int64); var b: int64 := items + EDI_PRICAT_ITEM_SIZE; poke64(b + EDI_PRICAT_GTIN, "04012345678918"c as int64); poke64(b + EDI_PRICAT_GTINLEN, 14); poke64(b + EDI_PRICAT_DESC, "Espressobohnen 1kg"c as int64); poke64(b + EDI_PRICAT_DESCLEN, 18); poke64(b + EDI_PRICAT_GROSSPRICE, 4950); poke64(b + EDI_PRICAT_NETPRICE, 4450); poke64(b + EDI_PRICAT_CURRENCY, "EUR"c as int64); poke64(b + EDI_PRICAT_CURRENCYLEN, 3); // GTIN vor dem Schreiben selbst pruefen - PRICAT tut es nicht if (EdiGtinCheck(peek64(a + EDI_PRICAT_GTIN) as pchar, 14) != 1) { PrintLn("GTIN ungueltig"); return 1; } var out: int64 := alloc(4096); var n: int64 := EdiPricatWrite(items, 2, out, 4096); PrintLn(Feld(out, n)); var it2: int64 := alloc(8 * EDI_PRICAT_ITEM_SIZE); var cnt: int64 := EdiPricatRead(out, n, it2, 8); PrintLn(StrConcat("Artikel: ", IntToStr(cnt))); i := 0; while (i < cnt) { var it: int64 := it2 + i * EDI_PRICAT_ITEM_SIZE; PrintLn(StrConcat(StrConcat(" ", Feld(peek64(it + EDI_PRICAT_GTIN), peek64(it + EDI_PRICAT_GTINLEN))), StrConcat(" netto/100: ", IntToStr(peek64(it + EDI_PRICAT_NETPRICE))))); i += 1; } // PARTIN: Stammdaten eines Partners var party: int64 := alloc(EDI_PARTY_SIZE); i := 0; while (i < EDI_PARTY_SIZE) { poke8(party + i, 0); i := i + 1; } poke64(party + EDI_PARTY_GLN, "4012345000009"c as int64); poke64(party + EDI_PARTY_GLNLEN, 13); poke64(party + EDI_PARTY_NAME, "Muster Handel GmbH"c as int64); poke64(party + EDI_PARTY_NAMELEN, 18); poke64(party + EDI_PARTY_STREET, "Hafenstrasse 12"c as int64); poke64(party + EDI_PARTY_STREETL, 15); poke64(party + EDI_PARTY_CITY, "Hamburg"c as int64); poke64(party + EDI_PARTY_CITYL, 7); poke64(party + EDI_PARTY_POSTCODE, "20457"c as int64); poke64(party + EDI_PARTY_POSTCODEL, 5); poke64(party + EDI_PARTY_COUNTRY, "DE"c as int64); poke64(party + EDI_PARTY_COUNTRYL, 2); poke64(party + EDI_PARTY_ROLE, "BY"c as int64); poke64(party + EDI_PARTY_ROLEL, 2); n := EdiPartinWrite(party, out, 4096); PrintLn(Feld(out, n)); return 0; } BGM+9+PRICAT+9'LIN+1++04012345678901:SRV'IMD+F++:::Kaffee gemahlen 500g'PRI+AAB:19.99:CP'PRI+AAA:17.99:CP'DTM+194:20260901:102'DTM+206:20261231:102'LIN+2++04012345678918:SRV'IMD+F++:::Espressobohnen 1kg'PRI+AAB:49.50:CP'PRI+AAA:44.50:CP'CNT+2:2' Artikel: 2 04012345678901 netto/100: 1799 04012345678918 netto/100: 4450 BGM+349++9'NAD+BY+4012345000009::9+Muster Handel GmbH+Hafenstrasse 12+Hamburg+20457+DE' ''PRI+AAB'' trägt den Brutto-, ''PRI+AAA'' den Nettopreis; ''DTM+194''/''DTM+206'' sind Beginn und Ende der Preisgültigkeit. Fehlt ein Gültigkeitsdatum, entfällt das jeweilige DTM-Segment (siehe zweiter Artikel). ---- ===== Imports ===== * ''std.edi.core'' * ''std.alloc'' ---- ===== Structs ===== ==== EdiPricatItem (EDI_PRICAT_ITEM_SIZE = 96 Bytes) ==== ^ Offset-Konstante ^ Inhalt ^ | ''EDI_PRICAT_GTIN / EDI_PRICAT_GTINLEN'' | GTIN-Zeiger und -Länge | | ''EDI_PRICAT_DESC / EDI_PRICAT_DESCLEN'' | Artikelbeschreibung | | ''EDI_PRICAT_GROSSPRICE'' | Bruttopreis × 100 (z. B. 299 = 2,99 €) | | ''EDI_PRICAT_NETPRICE'' | Nettopreis × 100 | | ''EDI_PRICAT_CURRENCY / EDI_PRICAT_CURRENCYLEN'' | Währungscode (z. B. "EUR") | | ''EDI_PRICAT_UNIT / EDI_PRICAT_UNITLEN'' | Mengeneinheit (z. B. "PCE", optional) | | ''EDI_PRICAT_VALIDFROM'' | Zeiger auf Gültigkeitsbeginn "YYYYMMDD" (0 = keins) | | ''EDI_PRICAT_VALIDTO'' | Zeiger auf Gültigkeitsende "YYYYMMDD" (0 = keins) | ==== EdiParty (EDI_PARTY_SIZE = 112 Bytes) ==== ^ Offset-Konstante ^ Inhalt ^ | ''EDI_PARTY_GLN / EDI_PARTY_GLNLEN'' | GLN-Zeiger und -Länge | | ''EDI_PARTY_NAME / EDI_PARTY_NAMELEN'' | Firmenname | | ''EDI_PARTY_STREET / EDI_PARTY_STREETL'' | Straße + Hausnummer | | ''EDI_PARTY_CITY / EDI_PARTY_CITYL'' | Ort | | ''EDI_PARTY_POSTCODE / EDI_PARTY_POSTCODEL'' | Postleitzahl | | ''EDI_PARTY_COUNTRY / EDI_PARTY_COUNTRYL'' | Ländercode (z. B. "DE") | | ''EDI_PARTY_ROLE / EDI_PARTY_ROLEL'' | Parteirolle (z. B. "SU", "BY") | ==== EdiProact (EDI_PROACT_SIZE = 40 Bytes) ==== Aktivitätsdaten (PROACT) für Warengruppen-Berichte. ^ Offset-Konstante ^ Inhalt ^ | ''EDI_PROACT_GTIN / EDI_PROACT_GTINLEN'' | GTIN-Zeiger und -Länge | | ''EDI_PROACT_QTY'' | Menge × 1000 (3 Dezimalstellen) | | ''EDI_PROACT_DATE'' | Zeiger auf Datum "YYYYMMDD" | | ''EDI_PROACT_TYPE'' | Aktivitätstyp: 1=Verkauf, 2=Rückgabe, 3=Transfer | ---- ===== Funktionen ===== ==== GS1-Validierung ==== ^ Signatur ^ Beschreibung ^ | ''EdiGtinCheck(ptr: pchar, len: int64): int64'' | Prüft GTIN-Prüfziffer (Mod-10). Gibt 1=gültig, 0=ungültig. Unterstützt Längen 8, 12, 13, 14. | | ''EdiGlnCheck(ptr: int64, len: int64): int64'' | Prüft GLN-Prüfziffer (Mod-10). Gibt 1=gültig, 0=ungültig. Erwartet exakt 13 Stellen. | ==== PRICAT ==== ^ Signatur ^ Beschreibung ^ | ''EdiPricatWrite(items: int64, count: int64, out: int64, outMax: int64): int64'' | Schreibt PRICAT. GTINs werden **nicht** validiert (Caller-Verantwortung). | | ''EdiPricatRead(buf: int64, bufLen: int64, items: int64, maxItems: int64): int64'' | Parst PRICAT; gibt Artikelanzahl zurück. Zero-Copy: Zeiger in ''items'' zeigen in ''buf''. | ==== PARTIN ==== ^ Signatur ^ Beschreibung ^ | ''EdiPartinWrite(party: int64, out: int64, outMax: int64): int64'' | Schreibt PARTIN (eine Partei) | | ''EdiPartinRead(buf: int64, bufLen: int64, party: int64): int64'' | Parst PARTIN; gibt ''EDI_OK'' oder Fehlercode | ---- ===== Codebeispiel — eingehenden Katalog prüfen ===== import std.edi.catalog; import std.alloc; import std.string; fn main(): int64 { // Zweite GTIN traegt absichtlich eine falsche Pruefziffer var msg: pchar := "BGM+9+PRICAT+9'LIN+1++04012345678901:SRV'PRI+AAA:17.99:CP'LIN+2++04012345678911:SRV'PRI+AAA:44.50:CP'CNT+2:2'"c; var items: int64 := alloc(64 * EDI_PRICAT_ITEM_SIZE); var count: int64 := EdiPricatRead(msg as int64, StrLen(msg), items, 64); PrintLn(StrConcat("Positionen: ", IntToStr(count))); var i: int64 := 0; while (i < count) { var item: int64 := items + i * EDI_PRICAT_ITEM_SIZE; var gptr: int64 := peek64(item + EDI_PRICAT_GTIN); var glen: int64 := peek64(item + EDI_PRICAT_GTINLEN); if (EdiGtinCheck(gptr as pchar, glen) == 0) { PrintLn(StrConcat("Ungueltige GTIN in Position ", IntToStr(i + 1))); } i := i + 1; } free(items, 64 * EDI_PRICAT_ITEM_SIZE); return 0; } Positionen: 2 Ungueltige GTIN in Position 2 ---- ===== Hinweise ===== * **Keine Prüfung beim Schreiben**: Weder ''EdiPricatWrite'' noch ''EdiPartinWrite'' prüfen GTIN oder GLN. Wer sich auf saubere Stammdaten verlässt, ruft ''EdiGtinCheck''/''EdiGlnCheck'' selbst auf — beim Erzeugen wie beim Einlesen. * **Preise sind ×100**: ''1799'' bedeutet 17,99 €. ''EDI_PRICAT_GROSSPRICE'' ist der Listen-, ''EDI_PRICAT_NETPRICE'' der Nettopreis. * **Gültigkeitsdaten sind Zeiger auf ''YYYYMMDD''** (8 Zeichen, ohne Längenfeld) oder 0. * **PARTIN schreibt eine Partei je Aufruf**: ''EdiPartinWrite'' erzeugt BGM+349 und ein NAD-Segment mit der Rolle aus ''EDI_PARTY_ROLE'' (''BY'' Käufer, ''SU'' Lieferant, ''DP'' Lieferstelle, ''IV'' Rechnungsempfänger). * **Structs vor dem Befüllen nullen** — ''EdiPricatWrite'' liest jedes Feld, auch die optionalen. ---- ===== Quelldatei ===== ^ Unit ^ Datei ^ | ''std.edi.catalog'' | ''std/edi/catalog.lyx'' | Letzte Aktualisierung: 2026-08-13 — beide Beispiele lauffähig gemacht und ausgeführt (lyxc 1.0.17K), PARTIN-Beispiel und Hinweisabschnitt 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).