Skip to content

Commit 7af9edb

Browse files
Avatarsiaclaude
andcommitted
fix(woocommerce): return single order per ImportGetAuftrag call
The caller in shopimport.php uses $result[0] per iteration of a for loop capped by ImportGetAuftraegeAnzahl() and maxmanuell. Returning 500 orders per call therefore silently dropped 499 of them while advancing the server-side after-cursor past them. Restores the historical 1-order contract; the after-filter still replaces the legacy 800-id include hack, and per-order persist gives us resume-after-crash semantics with at most one order lost per crash (consistent with pre-OpenXE-org#262 behaviour). MAX_PAGES_PER_RUN and ORDERS_PER_PAGE constants are removed; the caller loop (bounded by maxmanuell, default 100) now owns the batch size. Follow-up to review on OpenXE-org#262. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 7aef084 commit 7af9edb

1 file changed

Lines changed: 41 additions & 63 deletions

File tree

www/pages/shopimporter_woocommerce.php

Lines changed: 41 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,6 @@ class Shopimporter_Woocommerce extends ShopimporterBase
6969
/** @var bool $lastImportTimestampIsFallback True when lastImportTimestamp was computed as 30-day fallback */
7070
public $lastImportTimestampIsFallback = false;
7171

72-
const MAX_PAGES_PER_RUN = 5;
73-
const ORDERS_PER_PAGE = 100;
74-
7572
public function __construct($app, $intern = false)
7673
{
7774
$this->app = $app;
@@ -124,88 +121,69 @@ public function ImportGetAuftraegeAnzahl()
124121
}
125122

126123
/**
127-
* Queries the WooCommerce API for pending orders since the last import
128-
* timestamp and returns them as a Xentral-formatted array.
124+
* Queries the WooCommerce API for the oldest pending order since the last
125+
* import timestamp and returns it as a Xentral-formatted array with at most
126+
* one element. The caller (shopimport.php::RemoteGetAuftrag loop) expects
127+
* $result[0] per iteration; this contract must be maintained.
129128
*
130-
* Uses the WC v3 after= filter and paginates up to MAX_PAGES_PER_RUN
131-
* pages (500 orders max per run). Progress timestamp is persisted after
132-
* each processed order so aborted runs resume cleanly.
129+
* The after-filter advances per order so each caller-iteration fetches the
130+
* next order. A crash between RemoteGetAuftrag() and the shopimport_auftraege
131+
* INSERT loses at most this one order (consistent with pre-#262 behaviour).
133132
*
134-
* @return array|null
133+
* @return array Array with at most one order entry, or empty array if none.
135134
*/
136135
public function ImportGetAuftrag()
137136
{
138137
$data = $this->CatchRemoteCommand('data');
138+
$this->getKonfig($data['shopid'] ?? null, $data);
139139

140-
// Transition: if timestamp is still a fallback and a legacy ab_nummer
141-
// cursor is present, resolve it to a timestamp once.
140+
// Transition: ab_nummer -> timestamp once, if we still have the fallback.
142141
if ($this->lastImportTimestampIsFallback && !empty($data['ab_nummer'])) {
143142
$resolved = $this->resolveAbNummerToTimestamp((int) $data['ab_nummer']);
144143
if ($resolved !== null) {
145144
$this->persistLastImportTimestamp($resolved);
146145
}
147-
// lastImportTimestampIsFallback stays true only if resolution failed;
148-
// persistLastImportTimestamp() updated $this->lastImportTimestamp already.
149146
}
150147

151148
$configuredStatuses = array_map('trim', explode(';', (string) $this->statusPending));
152-
$runStartTimestamp = $this->lastImportTimestamp;
153-
$page = 1;
154-
$result = [];
155-
156-
while ($page <= self::MAX_PAGES_PER_RUN) {
157-
try {
158-
$pageOrders = $this->client->get('orders', [
159-
'status' => $configuredStatuses,
160-
'after' => $runStartTimestamp,
161-
'per_page' => self::ORDERS_PER_PAGE,
162-
'page' => $page,
163-
'orderby' => 'date',
164-
'order' => 'asc',
165-
]);
166-
} catch (Exception $e) {
167-
$this->logger->warning('WooCommerce ImportGetAuftrag page=' . $page . ': ' . $e->getMessage());
168-
break;
169-
}
170-
171-
if (empty($pageOrders)) {
172-
break;
173-
}
174149

175-
foreach ($pageOrders as $wcOrder) {
176-
if (is_null($wcOrder)) {
177-
continue;
178-
}
179-
180-
$order = $this->parseOrder($wcOrder);
181-
182-
$result[] = [
183-
'id' => $order['auftrag'],
184-
'sessionid' => '',
185-
'logdatei' => '',
186-
'warenkorb' => base64_encode(serialize($order)),
187-
];
150+
try {
151+
$pageOrders = $this->client->get('orders', [
152+
'status' => $configuredStatuses,
153+
'after' => $this->lastImportTimestamp,
154+
'per_page' => 1,
155+
'page' => 1,
156+
'orderby' => 'date',
157+
'order' => 'asc',
158+
]);
159+
} catch (Exception $e) {
160+
$this->logger->warning('WooCommerce ImportGetAuftrag: ' . $e->getMessage());
161+
return [];
162+
}
188163

189-
// Persist progress after every order so partial runs resume cleanly.
190-
if (!empty($wcOrder->date_created_gmt)) {
191-
$this->persistLastImportTimestamp((string) $wcOrder->date_created_gmt);
192-
}
193-
}
164+
if (empty($pageOrders)) {
165+
return [];
166+
}
194167

195-
$wcResponse = $this->client->getLastResponse();
196-
if ($wcResponse === null) {
197-
break;
198-
}
168+
$wcOrder = $pageOrders[0] ?? null;
169+
if ($wcOrder === null) {
170+
return [];
171+
}
199172

200-
$totalPages = (int) $wcResponse->getHeader('x-wp-totalpages');
201-
if ($totalPages < 1 || $page >= $totalPages) {
202-
break;
203-
}
173+
$order = $this->parseOrder($wcOrder);
204174

205-
$page++;
175+
// Persist progress for this order so the next Caller-iteration gets the
176+
// next order via the after-filter.
177+
if (!empty($wcOrder->date_created_gmt)) {
178+
$this->persistLastImportTimestamp((string) $wcOrder->date_created_gmt);
206179
}
207180

208-
return !empty($result) ? $result : null;
181+
return [[
182+
'id' => $order['auftrag'],
183+
'sessionid' => '',
184+
'logdatei' => '',
185+
'warenkorb' => base64_encode(serialize($order)),
186+
]];
209187
}
210188

211189
/**

0 commit comments

Comments
 (0)