@@ -41,7 +41,7 @@ und verlustfrei, ohne neue Plugin-Abhängigkeiten und ohne Wechsel der API-Versi
4141| Persistenz-Feld | ` shopexport.einstellungen_json ` → ` felder.letzter_import_timestamp ` | Bestehende Struktur nutzen, keine DB-Migration. |
4242| Timestamp-Format | ISO-8601 ` Y-m-d\TH:i:s ` (UTC) | Direkt an ` after= ` durchreichbar. |
4343| Caller-Cap (pre-existing) | ` shopexport.maxmanuell ` , default 100 | Der Batch-Cap liegt beim shopimport.php-Caller, nicht im Importer. |
44- | Cursor-Format | Tupel ` (letzter_import_timestamp, letzter_import_order_id ) ` | Loest Same-Second-Kollisionen via after=ts-1 + exclude= [ id ] . |
44+ | Cursor-Format | Tupel ` (letzter_import_timestamp, letzter_import_order_ids: [int] ) ` | IDs sammeln den aktuellen Sekunden-Bucket; -1s-Verschiebung greift nur mit mindestens einer ID . |
4545
4646## 4. Datei- und Funktions-Landkarte
4747
@@ -144,16 +144,30 @@ SELECT einstellungen_json FROM shopexport WHERE id = <shopid>
144144** Neu — Single-Order-Pseudocode:**
145145
146146```
147- afterTs = ts-1s (falls ts gesetzt)
148- query = orders?after=<afterTs>&per_page=1&orderby=date&order=asc
149- (+ exclude=[last_id] wenn last_id bekannt)
147+ # Fenster aufbauen
148+ if last_order_ids is not empty:
149+ after = last_ts - 1s
150+ exclude = last_order_ids
151+ else:
152+ after = last_ts
153+ exclude = (nicht gesetzt)
154+
155+ # Fetch
156+ order = client.get(orders, after=after, exclude=exclude, per_page=1, orderby=date, order=asc)[0]
150157
151158if response is empty:
152159 return []
153160
154161wcOrder = response[0]
155162order = parseOrder(wcOrder)
156163
164+ # Persist
165+ if order.date_created_gmt == last_ts:
166+ last_order_ids = last_order_ids + [order.id]
167+ else:
168+ last_ts = order.date_created_gmt
169+ last_order_ids = [order.id]
170+
157171persistLastImportCursor(order.date_created_gmt, order.id)
158172
159173return [{ id: order.auftrag, sessionid: '', logdatei: '', warenkorb: ... }]
@@ -303,7 +317,8 @@ Manuelle Integrationstests mit seeded Test-Orders.
303317| Andere Shopimporter erben Basisklasse-Struktur | niedrig | niedrig | Nur ` shopimporter_woocommerce.php ` anfassen, ` ShopimporterBase ` nicht anruehren |
304318| URL-Laengenlimits der WAF beim ` status[] ` -Array | sehr niedrig | niedrig | Typisch 2-3 Status-Werte, URL bleibt kurz |
305319| Caller-Kontrakt-Abweichung (1 vs. n Orders) | niedrig | hoch | Per Design Single-Order-Return; Caller-Loop fuer Volume-Handling |
306- | Timestamp-Kollision bei identischem date_created_gmt | niedrig | mittel | Adressiert durch Tupel-Cursor (ts, id) + exclude-Parameter |
320+ | Timestamp-Kollision bei identischem date_created_gmt | niedrig | mittel | Adressiert durch Tupel-Cursor + Bucket-Akkumulation (letzter_import_order_ids sammelt alle IDs des Buckets) |
321+ | Unbounded exclude-Liste bei grossem Bucket | niedrig | niedrig | In der Praxis kleine Listen; URL < 2 KB bei ~ 100 IDs |
307322
308323## 9. Definition of Done
309324
0 commit comments