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
bae0191
fix(woocommerce): expose response headers from inline WC client
Apr 20, 2026
1907cdf
fix(woocommerce): add getLastResponse() accessor on WC client
Apr 20, 2026
dee30b1
fix(woocommerce): persist last-import timestamp in shopexport config
Apr 20, 2026
ec9a617
fix(woocommerce): use after-filter and pagination for order import
Apr 20, 2026
b7d3a27
fix(woocommerce): stabilize after-filter across pagination run
Apr 20, 2026
810ae74
docs: add plan for woocommerce pagination fix
Apr 20, 2026
7a4ee0b
fix(woocommerce): CLI-context fallback for persistLastImportTimestamp
Apr 20, 2026
0d33e0e
revert(woocommerce): restore SSL-only gating for query-string basic auth
Apr 20, 2026
dfe8fbf
fix(woocommerce): return single order per ImportGetAuftrag call
Apr 20, 2026
1a07e3b
docs: update pagination plan to reflect single-order contract
Apr 20, 2026
d32c4c0
fix(woocommerce): return null (not empty array) from ImportGetAuftrag…
Apr 20, 2026
7099916
fix(woocommerce): remove broken getKonfig() re-init in ImportGetAuftrag
Apr 20, 2026
0af53ef
fix(woocommerce): run ab_nummer migration in the count path, too
Apr 20, 2026
78545a4
fix(woocommerce): tuple cursor (ts, id) to survive same-second orders
Apr 20, 2026
f3055b5
docs: extend pagination plan to cover tuple cursor and count-path mig…
Apr 20, 2026
dbddc49
fix(woocommerce): accumulate same-second order ids in cursor, gate -1…
Apr 20, 2026
e6dd616
docs: document bucket-accumulating cursor and gated -1s offset
Apr 20, 2026
726f2eb
fix(woocommerce): persist fallback cursor when ab_nummer resolution f…
Apr 21, 2026
11e1795
feat(woocommerce): use products/batch endpoints for stock sync
Apr 20, 2026
d7eb2c5
docs: add plan for batch stock sync
Apr 20, 2026
6a71d4b
fix(woocommerce): catch batch request exceptions, log success at info…
Apr 20, 2026
b1bc331
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