From 7768e542947bce6f875efa99e273f17bf9b9c499 Mon Sep 17 00:00:00 2001 From: Liborius Date: Fri, 1 May 2026 16:46:59 +0000 Subject: [PATCH] dojo: Variation-Client-Manipulation + Bundle-Components ohne stockLimitation --- ANTI-PATTERNS.md | 16 ++++++++++++ DOJO.md | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/ANTI-PATTERNS.md b/ANTI-PATTERNS.md index a956c51..e670ef9 100644 --- a/ANTI-PATTERNS.md +++ b/ANTI-PATTERNS.md @@ -308,3 +308,19 @@ if (!ct.includes('application/json')) throw new Error('Silent-Deny'); ``` --- + +## 20. POST auf `/rest/pim/variations/clients` + +**Was:** Auf dem PIM-Bulk-Pfad für Variations-Clients gibt es nur `DELETE` (entfernen) und `PUT` (hinzufügen/upsert). `POST` antwortet mit http 200 + `text/html` empty — klassisches Silent-Deny. Plenty's eigenes UI nutzt POST hier nicht. + +**Stattdessen:** PUT für Add (ist idempotent), DELETE für Remove. Siehe DOJO #35. + +--- + +## 21. `clients`-Property im PUT auf `/rest/items/{id}/variations/{vid}` setzen + +**Was:** Naheliegend wirkender Versuch, die Mandanten-Liste der Variation per Standard-PUT zu manipulieren: `PUT /rest/items/{id}/variations/{vid}` mit Body `{clients: [{plentyId, ...}]}`. Plenty antwortet **http 200 + JSON** mit der unveränderten Variation — der `clients`-Schlüssel im Body wird stillschweigend ignoriert. Besonders heimtückisch, weil Status + Content-Type alle Silent-Deny-Checks bestehen — der Verify-Read deckt es erst auf. + +**Stattdessen:** Den dedizierten Bulk-Pfad `/rest/pim/variations/clients` nutzen (DOJO #35). + +--- diff --git a/DOJO.md b/DOJO.md index 05a9a52..24a8852 100644 --- a/DOJO.md +++ b/DOJO.md @@ -992,3 +992,69 @@ if (!ct.includes('application/json')) throw new Error('Plenty Silent-Deny'); **Entdeckt:** 2026-05-01 nach mehrstündiger Recherche. Korrekter Endpoint gefunden via Browser-Network-Capture des Plenty-Backends; Plenty's eigenes UI nutzt genau diesen Bulk-Pfad. --- + +## 35. Variation-Client (Mandanten-Sichtbarkeit) Manipulation in Plenty Cloud + +**Lektion:** Mandanten-Sichtbarkeit pro Variation wird in Plenty Cloud über Add/Remove aus der `variationClients`-Liste gesteuert — es gibt **kein `isActive`-Flag pro Mandant**, anders als die UI suggeriert. Endpoints folgen dem PIM-Bulk-Pattern wie bei Tags (`/rest/pim/variations/` mit `[{variationId, plentyId}]`-Body), aber im Gegensatz zu Tags funktioniert hier auch PUT für Add (idempotent / upsert) — kein zweiter Pfad nötig. + +**Lese-Pfad** (sub-include auf Item-GET): +``` +GET /rest/items/{itemId}?with=variations.variationClients +→ main.variationClients = [{variationId, plentyId, isActive: true}, ...] + Inaktive Mandanten existieren in der Liste NICHT — fehlt = nicht aktiv. +``` + +**Mandant entfernen / Webshop deaktivieren:** +``` +DELETE /rest/pim/variations/clients +Body: [{variationId, plentyId}, ...] +← { affectedRows: N } (JSON, nicht text/html — Silent-Deny-Check!) +``` + +**Mandant hinzufügen / Webshop aktivieren:** +``` +PUT /rest/pim/variations/clients +Body: [{variationId, plentyId}, ...] +← [{variationId, plentyId}, ...] (Echo, JSON) +``` + +**Verworfene Kandidaten** (alle gemessen via Live-Probe): +- `PUT /rest/items/{id}/variations/{vid}` mit `clients`-Property → http 200 + JSON, aber `clients` wird **ignoriert** (silent no-op, gefährlich). +- `PUT /rest/pim/variations/{vid}` mit `clients`-Property → Silent-Deny (text/html empty). +- `PUT /rest/items/{id}/variations/{vid}/clients/{cid}` → Silent-Deny. +- `POST /rest/pim/variations/clients` → Silent-Deny (text/html empty). + +**Pattern:** +```javascript +const path = '/rest/pim/variations/clients'; +const body = [{ variationId, plentyId: clientPlentyId }]; +const resp = await client.request({ + method: present ? 'PUT' : 'DELETE', + url: path, data: body, validateStatus: () => true, +}); +const ct = String(resp.headers['content-type'] || ''); +if (!ct.includes('application/json')) throw new Error('Silent-Deny'); +// Verify per Re-Read von variationClients (Lese-Lag ≤ 2s). +``` + +**Entdeckt:** 2026-05-01 — Browser-Network-Capture des Plenty-Backends bestätigt, dass Plenty's eigene UI beim Mandanten-Häkchen-Toggle exakt diesen DELETE-Aufruf macht. + +--- + +## 36. `variationBundleComponents`-Sub-Include liefert kein `stockLimitation` + +**Lektion:** Beim Lesen von Bundle-Komponenten via `with=variations.variationBundleComponents,variations.stock` liefert Plenty pro Komponente nur `{rowId, componentVariationId, componentItemId, quantity, netStock, physicalStock}` — das `stockLimitation` der Komponenten-Variation ist **nicht** im Sub-Include. Wer es braucht (z.B. um „bestandsabhängig vs. unbegrenzt" pro Komponente zu erkennen), muss entweder pro Komponente einen separaten Item/Variation-Read machen oder eine domänenspezifische Annahme treffen. + +**Pattern (Annahme = limitiert):** +```javascript +// Wenn Use-Case Hardware-Bundles sind (echter Bestand erwartbar), +// reicht oft die Annahme stockLimitation=1: +const componentLimit = c => Math.floor((c.netStock ?? 0) / Math.max(1, c.quantity ?? 1)); +const paketBestand = Math.min(...components.map(componentLimit)); +``` + +**Wenn echtes `stockLimitation` zwingend ist:** zusätzlicher GET pro Komponenten-Variation (`/rest/items/{itemId}/variations/{variationId}`) — Vorsicht mit Roundtrip-Anzahl bei vielen Bundles. + +**Entdeckt:** 2026-05-01 — beim Aufbau einer Paket-Bestand-Berechnung über alle Bundles eines Bereichs. Initial mit `stockLimitation: 0`-Default getestet → Funktion lieferte immer `null`, weil ein Default 0 (=unbegrenzt) jeden Komponenten als "∞" einstuft. + +---