dojo: Variation-Client-Manipulation + Bundle-Components ohne stockLimitation
This commit is contained in:
@@ -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).
|
||||
|
||||
---
|
||||
|
||||
@@ -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/<resource>` 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.
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user