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