Skip to content

Commit eb378d7

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 bc7373a commit eb378d7

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 {
@@ -912,9 +927,10 @@ public function getKonfig($shopid, $data)
912927
$this->lastImportTimestampIsFallback = true;
913928
}
914929

915-
$this->lastImportOrderId = isset($preferences['felder']['letzter_import_order_id'])
916-
? (int) $preferences['felder']['letzter_import_order_id']
917-
: null;
930+
$storedIds = $preferences['felder']['letzter_import_order_ids'] ?? null;
931+
$this->lastImportOrderIds = is_array($storedIds)
932+
? array_values(array_filter(array_map('intval', $storedIds)))
933+
: [];
918934

919935
}
920936

@@ -931,11 +947,17 @@ public function persistLastImportTimestamp($isoUtcDate)
931947
}
932948

933949
/**
934-
* Persists the tuple cursor (timestamp + order id) to shopexport.einstellungen_json.
935-
* Does a read-modify-write to preserve all other fields.
950+
* Persists the tuple cursor (timestamp + accumulated order-id bucket) to
951+
* shopexport.einstellungen_json. Does a read-modify-write to preserve all
952+
* other fields.
953+
*
954+
* Bucket logic:
955+
* - $orderId === null → migration path; ids list is cleared.
956+
* - same timestamp as stored → append $orderId to the ids list.
957+
* - new timestamp → reset ids list to [$orderId].
936958
*
937959
* @param string $isoUtcDate ISO-8601 UTC timestamp, e.g. '2026-04-20T12:34:56'
938-
* @param int|null $orderId WooCommerce order ID, or null to clear
960+
* @param int|null $orderId WooCommerce order ID, or null (migration path)
939961
* @return void
940962
*/
941963
public function persistLastImportCursor($isoUtcDate, $orderId = null)
@@ -953,32 +975,51 @@ public function persistLastImportCursor($isoUtcDate, $orderId = null)
953975
"SELECT einstellungen_json FROM shopexport WHERE id = '$shopid' LIMIT 1"
954976
);
955977
}
956-
$einstellungen = [];
978+
$current = [];
957979
if (!empty($einstellungen_json)) {
958-
$einstellungen = json_decode($einstellungen_json, true) ?: [];
980+
$current = json_decode($einstellungen_json, true) ?: [];
981+
}
982+
if (!isset($current['felder']) || !is_array($current['felder'])) {
983+
$current['felder'] = [];
959984
}
960-
if (!isset($einstellungen['felder']) || !is_array($einstellungen['felder'])) {
961-
$einstellungen['felder'] = [];
985+
986+
$previousTs = $current['felder']['letzter_import_timestamp'] ?? null;
987+
$previousIds = $current['felder']['letzter_import_order_ids'] ?? [];
988+
if (!is_array($previousIds)) {
989+
$previousIds = [];
962990
}
963-
$einstellungen['felder']['letzter_import_timestamp'] = $isoUtcDate;
964-
if ($orderId !== null) {
965-
$einstellungen['felder']['letzter_import_order_id'] = (int) $orderId;
991+
992+
// Determine ids list for the new state.
993+
if ($orderId === null) {
994+
// Migration path — timestamp without a concrete order-id anchor.
995+
$newIds = [];
996+
} elseif ($previousTs !== null && $isoUtcDate === $previousTs) {
997+
// Same timestamp bucket — append id if not already present.
998+
$newIds = $previousIds;
999+
if (!in_array((int) $orderId, $newIds, true)) {
1000+
$newIds[] = (int) $orderId;
1001+
}
9661002
} else {
967-
unset($einstellungen['felder']['letzter_import_order_id']);
1003+
// New timestamp bucket — reset list to only this id.
1004+
$newIds = [(int) $orderId];
9681005
}
969-
$jsonEncoded = $this->app->DB->real_escape_string(json_encode($einstellungen));
1006+
1007+
$current['felder']['letzter_import_timestamp'] = $isoUtcDate;
1008+
$current['felder']['letzter_import_order_ids'] = $newIds;
1009+
1010+
$jsonEncoded = $this->app->DB->real_escape_string(json_encode($current));
9701011
if (!empty($this->app->DatabaseService)) {
9711012
$this->app->DatabaseService->execute(
9721013
"UPDATE shopexport SET einstellungen_json = :json WHERE id = :id",
973-
['json' => json_encode($einstellungen), 'id' => $shopid]
1014+
['json' => json_encode($current), 'id' => $shopid]
9741015
);
9751016
} else {
9761017
$this->app->DB->Update(
9771018
"UPDATE shopexport SET einstellungen_json = '$jsonEncoded' WHERE id = '$shopid'"
9781019
);
9791020
}
9801021
$this->lastImportTimestamp = $isoUtcDate;
981-
$this->lastImportOrderId = $orderId !== null ? (int) $orderId : null;
1022+
$this->lastImportOrderIds = $newIds;
9821023
}
9831024

9841025
/**

0 commit comments

Comments
 (0)