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/SupplierPartIDMenge: Attribut
ItemOut/@quantityLieferadresse:
OrderRequest/OrderRequestHeader/ShipTo/AddressRechnungsadresse:
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/IDTNRMenge:
IDOC/E1EDP01/MENGEMehrere
E1EDP19(jeQUALF) werden alle durchsucht. Eine 6-Buchstaben-IDTNRwird als Order-Code erkannt (positionHasValidIdtnr()prüft[A-Z]{6}), eine numerischeIDTNRals 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"](Fallbacktype="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 |
|---|---|---|
Position identifizieren | numerische | 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 |
|---|---|---|---|---|---|
openTRANS (v1.0/2.1) | nein (nur Order-Code) | nein | nein | ja | ja |
cXML | ja ( | ja | ja | ja | ja |
ORDER05 (SAP IDoc) | ja ( | ja | ja | ja | ja |
generisches XML | ja ( | ja | ja | ja | ja |
EDIFACT | nein (nur Order-Code) | nein | nein | ja | ja |
4. Voraussetzungen im Shop (Grundeinstellungen)
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 ( |
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).