Skip to content

Commit dbddc49

Browse files
Avatarsiaclaude
andcommitted
fix(woocommerce): accumulate same-second order ids in cursor, gate -1s offset
Bei identischem date_created_gmt mehrerer Orders hielt exclude nur die zuletzt importierte ID. Nach zwei Orders im selben Bucket wurde die erste wieder sichtbar und Count- wie Fetch-Pfad liefen in eine Endlosschleife. Cursor persistiert jetzt die komplette Liste aller IDs innerhalb des aktuellen Sekunden-Buckets (felder.letzter_import_order_ids als JSON- Array). Bei Bucket-Wechsel wird die Liste zurueckgesetzt; bei gleichem Bucket wird die neue ID angehaengt. Gleichzeitig wird die -1s-Korrektur am Query gated: nur wenn mindestens eine exclude-ID bekannt ist, wird der after-Filter um 1 Sekunde nach hinten verschoben. Dadurch entfaellt die Doppel-Subtraktion nach der ab_nummer-Migration (resolveAbNummerToTimestamp schon -1s, Query war nochmal -1s -> 2s zurueck in der Vergangenheit). Der Erstlauf nach Migration liefert jetzt exakt die ab_nummer-Order als Startpunkt. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent f3055b5 commit dbddc49

1 file changed

Lines changed: 79 additions & 38 deletions

File tree

www/pages/shopimporter_woocommerce.php

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

72-
/** @var int|null $lastImportOrderId WooCommerce order ID of the last successfully imported order */
73-
public $lastImportOrderId = null;
72+
/** @var int[] $lastImportOrderIds WooCommerce order IDs within the current timestamp bucket */
73+
public $lastImportOrderIds = [];
7474

7575
public function __construct($app, $intern = false)
7676
{
@@ -99,14 +99,20 @@ public function ImportGetAuftraegeAnzahl()
9999

100100
$configuredStatuses = array_map('trim', explode(';', (string) $this->statusPending));
101101

102-
$afterTs = gmdate('Y-m-d\TH:i:s', max(0, strtotime($this->lastImportTimestamp) - 1));
103-
$queryArgs = [
104-
'status' => $configuredStatuses,
105-
'after' => $afterTs,
106-
'per_page' => 1,
107-
];
108-
if (!empty($this->lastImportOrderId)) {
109-
$queryArgs['exclude'] = [(int) $this->lastImportOrderId];
102+
if (!empty($this->lastImportOrderIds)) {
103+
$afterTs = gmdate('Y-m-d\TH:i:s', max(0, strtotime($this->lastImportTimestamp) - 1));
104+
$queryArgs = [
105+
'status' => $configuredStatuses,
106+
'after' => $afterTs,
107+
'per_page' => 1,
108+
'exclude' => array_values($this->lastImportOrderIds),
109+
];
110+
} else {
111+
$queryArgs = [
112+
'status' => $configuredStatuses,
113+
'after' => $this->lastImportTimestamp,
114+
'per_page' => 1,
115+
];
110116
}
111117

112118
try {
@@ -151,17 +157,26 @@ public function ImportGetAuftrag()
151157

152158
$configuredStatuses = array_map('trim', explode(';', (string) $this->statusPending));
153159

154-
$afterTs = gmdate('Y-m-d\TH:i:s', max(0, strtotime($this->lastImportTimestamp) - 1));
155-
$queryArgs = [
156-
'status' => $configuredStatuses,
157-
'after' => $afterTs,
158-
'per_page' => 1,
159-
'page' => 1,
160-
'orderby' => 'date',
161-
'order' => 'asc',
162-
];
163-
if (!empty($this->lastImportOrderId)) {
164-
$queryArgs['exclude'] = [(int) $this->lastImportOrderId];
160+
if (!empty($this->lastImportOrderIds)) {
161+
$afterTs = gmdate('Y-m-d\TH:i:s', max(0, strtotime($this->lastImportTimestamp) - 1));
162+
$queryArgs = [
163+
'status' => $configuredStatuses,
164+
'after' => $afterTs,
165+
'per_page' => 1,
166+
'page' => 1,
167+
'orderby' => 'date',
168+
'order' => 'asc',
169+
'exclude' => array_values($this->lastImportOrderIds),
170+
];
171+
} else {
172+
$queryArgs = [
173+
'status' => $configuredStatuses,
174+
'after' => $this->lastImportTimestamp,
175+
'per_page' => 1,
176+
'page' => 1,
177+
'orderby' => 'date',
178+
'order' => 'asc',
179+
];
165180
}
166181

167182
try {
@@ -941,9 +956,10 @@ public function getKonfig($shopid, $data)
941956
$this->lastImportTimestampIsFallback = true;
942957
}
943958

944-
$this->lastImportOrderId = isset($preferences['felder']['letzter_import_order_id'])
945-
? (int) $preferences['felder']['letzter_import_order_id']
946-
: null;
959+
$storedIds = $preferences['felder']['letzter_import_order_ids'] ?? null;
960+
$this->lastImportOrderIds = is_array($storedIds)
961+
? array_values(array_filter(array_map('intval', $storedIds)))
962+
: [];
947963

948964
}
949965

@@ -960,11 +976,17 @@ public function persistLastImportTimestamp($isoUtcDate)
960976
}
961977

962978
/**
963-
* Persists the tuple cursor (timestamp + order id) to shopexport.einstellungen_json.
964-
* Does a read-modify-write to preserve all other fields.
979+
* Persists the tuple cursor (timestamp + accumulated order-id bucket) to
980+
* shopexport.einstellungen_json. Does a read-modify-write to preserve all
981+
* other fields.
982+
*
983+
* Bucket logic:
984+
* - $orderId === null → migration path; ids list is cleared.
985+
* - same timestamp as stored → append $orderId to the ids list.
986+
* - new timestamp → reset ids list to [$orderId].
965987
*
966988
* @param string $isoUtcDate ISO-8601 UTC timestamp, e.g. '2026-04-20T12:34:56'
967-
* @param int|null $orderId WooCommerce order ID, or null to clear
989+
* @param int|null $orderId WooCommerce order ID, or null (migration path)
968990
* @return void
969991
*/
970992
public function persistLastImportCursor($isoUtcDate, $orderId = null)
@@ -982,32 +1004,51 @@ public function persistLastImportCursor($isoUtcDate, $orderId = null)
9821004
"SELECT einstellungen_json FROM shopexport WHERE id = '$shopid' LIMIT 1"
9831005
);
9841006
}
985-
$einstellungen = [];
1007+
$current = [];
9861008
if (!empty($einstellungen_json)) {
987-
$einstellungen = json_decode($einstellungen_json, true) ?: [];
1009+
$current = json_decode($einstellungen_json, true) ?: [];
1010+
}
1011+
if (!isset($current['felder']) || !is_array($current['felder'])) {
1012+
$current['felder'] = [];
9881013
}
989-
if (!isset($einstellungen['felder']) || !is_array($einstellungen['felder'])) {
990-
$einstellungen['felder'] = [];
1014+
1015+
$previousTs = $current['felder']['letzter_import_timestamp'] ?? null;
1016+
$previousIds = $current['felder']['letzter_import_order_ids'] ?? [];
1017+
if (!is_array($previousIds)) {
1018+
$previousIds = [];
9911019
}
992-
$einstellungen['felder']['letzter_import_timestamp'] = $isoUtcDate;
993-
if ($orderId !== null) {
994-
$einstellungen['felder']['letzter_import_order_id'] = (int) $orderId;
1020+
1021+
// Determine ids list for the new state.
1022+
if ($orderId === null) {
1023+
// Migration path — timestamp without a concrete order-id anchor.
1024+
$newIds = [];
1025+
} elseif ($previousTs !== null && $isoUtcDate === $previousTs) {
1026+
// Same timestamp bucket — append id if not already present.
1027+
$newIds = $previousIds;
1028+
if (!in_array((int) $orderId, $newIds, true)) {
1029+
$newIds[] = (int) $orderId;
1030+
}
9951031
} else {
996-
unset($einstellungen['felder']['letzter_import_order_id']);
1032+
// New timestamp bucket — reset list to only this id.
1033+
$newIds = [(int) $orderId];
9971034
}
998-
$jsonEncoded = $this->app->DB->real_escape_string(json_encode($einstellungen));
1035+
1036+
$current['felder']['letzter_import_timestamp'] = $isoUtcDate;
1037+
$current['felder']['letzter_import_order_ids'] = $newIds;
1038+
1039+
$jsonEncoded = $this->app->DB->real_escape_string(json_encode($current));
9991040
if (!empty($this->app->DatabaseService)) {
10001041
$this->app->DatabaseService->execute(
10011042
"UPDATE shopexport SET einstellungen_json = :json WHERE id = :id",
1002-
['json' => json_encode($einstellungen), 'id' => $shopid]
1043+
['json' => json_encode($current), 'id' => $shopid]
10031044
);
10041045
} else {
10051046
$this->app->DB->Update(
10061047
"UPDATE shopexport SET einstellungen_json = '$jsonEncoded' WHERE id = '$shopid'"
10071048
);
10081049
}
10091050
$this->lastImportTimestamp = $isoUtcDate;
1010-
$this->lastImportOrderId = $orderId !== null ? (int) $orderId : null;
1051+
$this->lastImportOrderIds = $newIds;
10111052
}
10121053

10131054
/**

0 commit comments

Comments
 (0)