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