@@ -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