Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
eeae728
fix(woocommerce): expose response headers from inline WC client
Apr 20, 2026
309b72e
fix(woocommerce): add getLastResponse() accessor on WC client
Apr 20, 2026
a9845ef
fix(woocommerce): persist last-import timestamp in shopexport config
Apr 20, 2026
7a4a80e
fix(woocommerce): use after-filter and pagination for order import
Apr 20, 2026
069e02a
fix(woocommerce): stabilize after-filter across pagination run
Apr 20, 2026
48bd84c
docs: add plan for woocommerce pagination fix
Apr 20, 2026
dd6c4b1
fix(woocommerce): CLI-context fallback for persistLastImportTimestamp
Apr 20, 2026
bea289a
revert(woocommerce): restore SSL-only gating for query-string basic auth
Apr 20, 2026
c1543d0
fix(woocommerce): return single order per ImportGetAuftrag call
Apr 20, 2026
867794b
docs: update pagination plan to reflect single-order contract
Apr 20, 2026
fe9e560
fix(woocommerce): return null (not empty array) from ImportGetAuftrag…
Apr 20, 2026
554030e
fix(woocommerce): remove broken getKonfig() re-init in ImportGetAuftrag
Apr 20, 2026
307cc4a
fix(woocommerce): run ab_nummer migration in the count path, too
Apr 20, 2026
351dd63
fix(woocommerce): tuple cursor (ts, id) to survive same-second orders
Apr 20, 2026
cf0162e
docs: extend pagination plan to cover tuple cursor and count-path mig…
Apr 20, 2026
56d68c2
fix(woocommerce): accumulate same-second order ids in cursor, gate -1…
Apr 20, 2026
d53649d
docs: document bucket-accumulating cursor and gated -1s offset
Apr 20, 2026
b887f00
fix(woocommerce): persist fallback cursor when ab_nummer resolution f…
Apr 21, 2026
45ecd71
feat(woocommerce): use products/batch endpoints for stock sync
Apr 20, 2026
6495a07
docs: add plan for batch stock sync
Apr 20, 2026
a70b864
fix(woocommerce): catch batch request exceptions, log success at info…
Apr 20, 2026
14268eb
fix(woocommerce): catch SKU-lookup exceptions per chunk in stock sync
Apr 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions docs/plans/woocommerce-batch-stock-sync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# WooCommerce Batch Stock Sync — Plan

Companion document to [GitHub Issue #263](https://github.com/OpenXE-org/OpenXE/issues/263)
and the `feature/woocommerce-batch-stock-sync` branch.

---

## §1 Ziel

`ImportSendListLager()` bisher: 2 HTTP-Requests pro Artikel (SKU-Lookup + PUT).
Bei 1.000 Artikeln = 2.000 Requests — langsam, rate-limit-anfällig, kein Partial-Error-Handling.

Ziel: Nutzung der offiziellen WC REST v3 Batch-Endpoints, um den Request-Count auf
`ceil(n/100)` SKU-Lookups + `ceil(n/100)` Batch-Updates zu reduzieren (~20 statt 2.000).

---

## §2 Scope

### IN
- Refactor von `ImportSendListLager()` in `www/pages/shopimporter_woocommerce.php`
- Neue private Hilfsmethode `processBatchResponse()` in derselben Klasse
- Plan-Dokument `docs/plans/woocommerce-batch-stock-sync.md`

### OUT
- Kein neuer `postBatch()`-Helper auf `WCClient` — `post()` reicht direkt
- Keine Änderungen an `ImportGetAuftrag*`, `getKonfig`, `parseOrder`
- Kein Retry-Mechanismus bei HTTP-Fehlern (separater Task)
- Kein DB-Schema-Change
- Kein PR-Open (nach Review durch Maintainer)

---

## §3 Fix-Parameter

| Parameter | Wert | Begründung |
|---|---|---|
| Batch-Size | 100 Items | WC REST v3 Maximum |
| SKU-Chunk-Size | 100 SKUs | Passend zu `per_page=100` |
| Retry | Keiner | Out-of-scope für diesen PR |
| SKU-CSV-Support | `?sku=a,b,c` | WC REST v3 akzeptiert kommaseparierte Liste |

---

## §4 Funktions-Landkarte

Nur `ImportSendListLager()` wird geändert. Neue private Methode `processBatchResponse()`.

```
ImportSendListLager()
├── Schritt 1: Alle SKUs + Stock-Params sammeln (pendingUpdates[])
├── Schritt 2: Bulk-SKU-Auflösung
│ └── GET products?sku=<csv>&per_page=100 (je Chunk à 100 SKUs)
│ → skuMap[sku] = {id, parent, isvariant}
├── Schritt 3: Gruppieren
│ ├── simpleItems[] (für products/batch)
│ └── variationItems[parent_id][] (für products/{id}/variations/batch)
└── Schritt 4: Batch-Updates senden (je Chunk à 100)
├── POST products/batch {update: [...]}
├── POST products/{parent}/variations/batch {update: [...]}
└── processBatchResponse() → Partial-Error-Logging, zählt Erfolge

processBatchResponse($response, $endpoint)
├── Iteriert response->update[]
│ ├── item->error vorhanden → logger->error
│ └── kein Fehler → successCount++
└── Iteriert response->errors[] (WC-Fallback)
```

---

## §5 Implementierungsschritte

1. **Vorverlagerte Datensammlung:** Statt der bisherigen per-Artikel-Schleife erst alle SKUs
und Stock-Params in `$pendingUpdates[]` sammeln.

2. **Bulk-SKU-Auflösung:** `GET products?sku=<csv>&per_page=100` in Chunks à 100 SKUs.
Ergebnis in `$skuMap[sku]` cachen.

3. **Gruppierung:** Simple products in `$simpleItems[]`, Variations pro Parent-ID in
`$variationItems[parent_id][]`.

4. **Batch-POST:** `$this->client->post('products/batch', ['update' => $chunk])` für
simple products; analog für Variations.

5. **Partial-Error-Handling:** `processBatchResponse()` liest `response->update[]` und
`response->errors[]`, loggt Fehler per Item ohne den restlichen Sync abzubrechen.

---

## §6 Test-Matrix

Testumgebung: Docker-Shop auf `192.168.0.143:8080`, WC 10.7, Consumer Keys aktiv.

| # | Szenario | Erwartetes Ergebnis |
|---|---|---|
| T1 | 1 Artikel | 1 SKU-GET + 1 Batch-POST, Lagerbestand korrekt |
| T2 | 100 Artikel | 1 SKU-GET + 1 Batch-POST (1 Chunk) |
| T3 | 250 Artikel | 3 SKU-GETs + 3 Batch-POSTs (100+100+50) |
| T4 | 1 falsche SKU in 100er-Batch | 99 korrekt updated, 1 Error geloggt, sync läuft durch |
| T5 | Variation (parent != 0) | Variation-Batch-Endpoint genutzt, nicht products/batch |
| T6 | `ausverkauft=1` | stock_quantity=0 im Batch-Item |
| T7 | `inaktiv=1` | status='private' im Batch-Item |
| T8 | `pseudolager` gesetzt | lageranzahl aus pseudolager, nicht anzahl_lager |
| T9 | Leere Artikelliste | Rückgabe 0, keine HTTP-Requests |

---

## §7 Rollout & Rückwärts-Kompatibilität

- **Interface unverändert:** `ImportSendListLager()` behält Signatur `(): int`.
- **Keine DB-Migration** erforderlich.
- **WC-Mindestversion:** REST v3 Batch-Endpoints seit WC 3.0 (2017) — unkritisch.
- **Rollback:** Git-Revert des Feature-Branch reicht.

---

## §8 Risiken

| Risiko | Mitigation |
|---|---|
| WC akzeptiert SKU-CSV nicht (`?sku=a,b`) | Verifikation in T1–T3 gegen 192.168.0.143:8080 — falls nicht, Fallback: sequentielle Einzellookups (wie vorher) |
| Batch-Response enthält keine `update`-Keys | `processBatchResponse()` defensiv mit `?? []` abgesichert |
| Hoster-seitiger `per_page`-Cap unter 100 | Derzeit nicht abgefangen; separater Task |
| Partial-Error zählt als nicht-erfolgreich | Korrekt: `$anzahl` zählt nur Items ohne Fehler |
| Variations mit unbekanntem Parent | Variation-Batch schlägt fehl → WCHttpClientException propagiert nach oben (bestehende Semantik) |
Loading