OCI-Rückantwort: Bestellpositionen in den verschiedenen Formaten übergeben

OCI-Rückantwort: Bestellpositionen in den verschiedenen Formaten übergeben

Dieser Artikel beschreibt, wie eine Bestellposition in der OCI-Rückantwort an printlounge adressiert wird – pro unterstütztem Format – und warum openTRANS dabei grundlegend anders funktioniert als die übrigen Formate. Die Aussagen gelten für den Release-/Rückantwort-Flow (OciReleaseOrderController::releaseOrder()).

1. Pro Format: Wo die Positions-ID im Dokument steht

In cXML, ORDER05 und generischem XML trägt jede Zeile ein strukturiertes Identifier-Feld. In dieses Feld schreibt der Procurement-Provider – je nach partId-Setting – entweder den Order-Code oder die numerische order_cart_id.

1.1 cXML

  • Identifier: cXML/Request/OrderRequest/ItemOut/ItemID/SupplierPartID

  • Menge: Attribut ItemOut/@quantity

  • Lieferadresse: OrderRequest/OrderRequestHeader/ShipTo/Address

  • Rechnungsadresse: OrderRequest/OrderRequestHeader/BillTo/Address

<cXML> <Request> <OrderRequest> <OrderRequestHeader> <ShipTo><Address><!-- Lieferadresse --></Address></ShipTo> <BillTo><Address><!-- Rechnungsadresse --></Address></BillTo> </OrderRequestHeader> <ItemOut quantity="10"> <ItemID> <SupplierPartID>127859</SupplierPartID> <!-- order_cart_id (bei partId=Bestellposition) --> </ItemID> </ItemOut> </OrderRequest> </Request> </cXML>

1.2 ORDER05 (SAP IDoc)

  • Identifier: IDOC/E1EDP01/E1EDP19/IDTNR

  • Menge: IDOC/E1EDP01/MENGE

  • Mehrere E1EDP19 (je QUALF) werden alle durchsucht. Eine 6-Buchstaben-IDTNR wird als Order-Code erkannt (positionHasValidIdtnr() prüft [A-Z]{6}), eine numerische IDTNR als Position.

<IDOC> <E1EDP01> <MENGE>10</MENGE> <E1EDP19> <IDTNR>127859</IDTNR> <!-- order_cart_id (bei partId=Bestellposition) --> </E1EDP19> </E1EDP01> </IDOC>

1.3 Generisches XML (OrderDetail)

  • Identifier: …/ItemDetail/BaseItemDetail/ItemIdentifiers/PartNumbers/SubstitutePartNumbers/ListOfProductIdentifierCoded/ProductIdentifierCoded/ProductIdentifier
    (Fallback: …/SellerPartNumber/PartNum/PartID)

  • Menge: BaseItemDetail/TotalQuantity/Quantity/QuantityValue

<OrderDetail> <ListOfItemDetail> <ItemDetail> <BaseItemDetail> <ItemIdentifiers> <PartNumbers> <SubstitutePartNumbers> <ListOfProductIdentifierCoded> <ProductIdentifierCoded> <ProductIdentifier>127859</ProductIdentifier> <!-- order_cart_id --> </ProductIdentifierCoded> </ListOfProductIdentifierCoded> </SubstitutePartNumbers> </PartNumbers> </ItemIdentifiers> <TotalQuantity><Quantity><QuantityValue>10</QuantityValue></Quantity></TotalQuantity> </BaseItemDetail> </ItemDetail> </ListOfItemDetail> </OrderDetail>

1.4 openTRANS (Sonderfall – siehe Abschnitt 2)

  • Identifier: ORDER/ORDER_ITEM_LIST/ORDER_ITEM/REMARK[@type="general"] (Fallback type="comment")

  • Menge: ORDER_ITEM/QUANTITY

<ORDER version="2.1"> <ORDER_ITEM_LIST> <ORDER_ITEM> <QUANTITY>10</QUANTITY> <REMARK type="general">OTQJPL</REMARK> <!-- nur Order-Code, KEINE numerische Position --> </ORDER_ITEM> </ORDER_ITEM_LIST> </ORDER>

1.5 EDIFACT

EDIFACT liefert keine Positionsliste (erbt getAllOrderCodes() = leer) und kennt nur einen Order-Code (aus dem FREE_TEXT-Segment, General Information). Damit ist – wie bei openTRANS – keine Positions-Granularität möglich.

2. Warum openTRANS anders ist

Der Unterschied ist betrifft die gesamte Positions-Adressierung.

2.1 Strukturiertes Identifier-Feld vs. Freitext-Remark

cXML, ORDER05 und generisches XML besitzen ein dediziertes, frei belegbares Identifier-Feld pro Zeile (SupplierPartID, IDTNR, ProductIdentifier). Dieses Feld ist dafür gedacht, eine lieferantenseitige Kennung aufzunehmen – printlounge legt dort wahlweise den Order-Code oder die numerische order_cart_id ab. Weil es ein echtes, zahlenfähiges Identifier-Feld ist, lässt sich jede Procurement-Zeile 1:1 auf eine printlounge-Cart-Position abbilden.

openTRANS hat zwar eigene Produkt-Felder (SUPPLIER_PID, PRODUCT_ID), aber die printlounge-Integration nutzt diese nicht. Sie liest den printlounge-Order-Code aus dem Freitext-Feld REMARK[@type="general"] und extrahiert daraus per extractOrderCodeFromString() einen Code aus 5+ Großbuchstaben (auf 6 Zeichen gekürzt):

preg_match('/^([A-Z]{5,})/', $value, $matches)

Eine numerische order_cart_id überlebt diese Extraktion nicht – sie besteht aus Ziffern. openTRANS kann eine Position daher niemals per order_cart_id adressieren, sondern ausschließlich per Order-Code.

2.2 Die Arbeitseinheit ist die Order, nicht die Position

Daraus folgt das openTRANS-Modell: „eine Procurement-Zeile = eine printlounge-Order (Order-Code)". Mehrere ORDER_ITEM mit demselben Order-Code werden in getAllOrderCodes() zu einem Eintrag zusammengefasst. Konsequenzen über alle Funktionen hinweg:

Funktion

cXML / ORDER05 / generisches XML

openTRANS

Funktion

cXML / ORDER05 / generisches XML

openTRANS

Position identifizieren

numerische order_cart_id möglich

nur Order-Code

Menge/Preis aktualisieren

pro Position

nur auf Order-Ebene (erste Artikelposition)

Einzel-Position stornieren

ja (fehlende Positionen werden storniert)

nein – nur Ganz-Storno

Adressen ändern

ja (Order-Ebene)

ja (Order-Ebene)

Adressen sind in allen Formaten eine Order-Eigenschaft (Liefer-/Rechnungsadresse der ganzen Bestellung), nie positionsbezogen.

2.3 Stornierung in openTRANS

Da openTRANS keine Position einzeln adressieren kann, trifft die Stornierung immer die ganze Order (cancelOrder() setzt order_status = 69 und ruft cancelItem() auf jede Position). Der Storno wird nicht im XML signalisiert – der openTRANS-Parser liest kein Cancel-Flag –, sondern über den Request-Parameter status = 69 (OrderService::ORDER_STATUS_CANCELLATION). Optional grenzt der Request-Parameter order_code auf genau eine Order ein.

Einzel-Positions-Storno via openTRANS ist nur möglich, wenn jede Bestellposition als eigene printlounge-Order (eigener Order-Code) modelliert ist. Andernfalls auf cXML/ORDER05/generisches XML mit partId = Bestellposition wechseln.

3. Zusammenfassung (Capability-Matrix)

Format

Position per ID adressierbar

Menge/Preis pro Position

Einzel-Storno

Ganz-Storno

Adressen

Format

Position per ID adressierbar

Menge/Preis pro Position

Einzel-Storno

Ganz-Storno

Adressen

openTRANS (v1.0/2.1)

nein (nur Order-Code)

nein

nein

ja

ja

cXML

ja (SupplierPartID)

ja

ja

ja

ja

ORDER05 (SAP IDoc)

ja (E1EDP19/IDTNR)

ja

ja

ja

ja

generisches XML

ja (ProductIdentifier)

ja

ja

ja

ja

EDIFACT

nein (nur Order-Code)

nein

nein

ja

ja

4. Voraussetzungen im Shop (Grundeinstellungen)

Ziel

Notwendige Einstellung

Ziel

Notwendige Einstellung

Freigabe überhaupt

Funktion aktivieren? = Ja und Freigabeworkflow aktivieren? = Ja

Preise & Mengen ändern

Preis und Menge aktualisieren? = Ja

Einzelne Position stornieren

PartID / IDTNR = Bestellposition (order_cart_id) – nicht für openTRANS/EDIFACT

Adressen ändern

keine Extra-Einstellung (kommt automatisch aus der Rückantwort)

Mehrfaches Nachändern erlauben

Mehrfache Freigaben unterbinden = Nein

5. Randnotiz: Cost-Center

Die positionsweise Cost-Center-Zuordnung (order_cart.cstctr / s_cstctr) wird ausschließlich für openTRANS aus ACCOUNTING_INFO/COST_CATEGORY_ID[@type="cost_center"] befüllt. Sie ist unabhängig vom oben beschriebenen Positions-Identifier und nutzt einen eigenen, streng validierten Positions-Match (gleiche Item-Anzahl + Mengen-/Preis-Abgleich pro Position).