@pisell/pisellos 2.2.190 → 2.2.191

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/model/strategy/adapter/promotion/index.js +0 -9
  2. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +2 -1
  3. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +2 -7
  4. package/dist/modules/Cart/utils/cartProduct.js +13 -2
  5. package/dist/modules/Order/index.d.ts +1 -3
  6. package/dist/modules/Order/index.js +69 -95
  7. package/dist/modules/Order/types.d.ts +9 -6
  8. package/dist/modules/Order/utils.d.ts +9 -2
  9. package/dist/modules/Order/utils.js +36 -13
  10. package/dist/modules/SalesSummary/types.d.ts +3 -1
  11. package/dist/modules/SalesSummary/utils.js +7 -3
  12. package/dist/server/modules/order/index.d.ts +126 -6
  13. package/dist/server/modules/order/index.js +1204 -285
  14. package/dist/server/modules/order/types.d.ts +0 -2
  15. package/dist/server/modules/products/index.d.ts +90 -6
  16. package/dist/server/modules/products/index.js +1017 -361
  17. package/dist/solution/BaseSales/index.js +13 -7
  18. package/dist/solution/BaseSales/types.d.ts +8 -5
  19. package/dist/solution/BaseSales/types.js +2 -3
  20. package/dist/solution/BaseSales/utils/cartPromotion.js +7 -7
  21. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  22. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +16 -13
  23. package/dist/solution/BaseSales/utils.d.ts +1 -1
  24. package/dist/solution/BaseSales/utils.js +22 -19
  25. package/dist/solution/BookingByStep/index.d.ts +1 -1
  26. package/dist/solution/BookingTicket/index.d.ts +1 -1
  27. package/dist/solution/ScanOrder/index.js +7 -5
  28. package/dist/solution/ScanOrder/types.d.ts +8 -5
  29. package/dist/solution/ScanOrder/types.js +2 -3
  30. package/dist/solution/ScanOrder/utils.d.ts +1 -1
  31. package/dist/solution/ScanOrder/utils.js +26 -23
  32. package/dist/solution/VenueBooking/index.js +5 -3
  33. package/dist/solution/VenueBooking/sales-section-4-annotated.json +0 -2
  34. package/lib/model/strategy/adapter/promotion/index.js +0 -49
  35. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +2 -1
  36. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +2 -1
  37. package/lib/modules/Cart/utils/cartProduct.js +9 -2
  38. package/lib/modules/Order/index.d.ts +1 -3
  39. package/lib/modules/Order/index.js +45 -58
  40. package/lib/modules/Order/types.d.ts +9 -6
  41. package/lib/modules/Order/utils.d.ts +9 -2
  42. package/lib/modules/Order/utils.js +41 -10
  43. package/lib/modules/SalesSummary/types.d.ts +3 -1
  44. package/lib/modules/SalesSummary/utils.js +5 -3
  45. package/lib/server/modules/order/index.d.ts +126 -6
  46. package/lib/server/modules/order/index.js +722 -42
  47. package/lib/server/modules/order/types.d.ts +0 -2
  48. package/lib/server/modules/products/index.d.ts +90 -6
  49. package/lib/server/modules/products/index.js +492 -30
  50. package/lib/solution/BaseSales/index.js +14 -5
  51. package/lib/solution/BaseSales/types.d.ts +8 -5
  52. package/lib/solution/BaseSales/utils/cartPromotion.js +6 -6
  53. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  54. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +21 -14
  55. package/lib/solution/BaseSales/utils.d.ts +1 -1
  56. package/lib/solution/BaseSales/utils.js +11 -7
  57. package/lib/solution/BookingByStep/index.d.ts +1 -1
  58. package/lib/solution/BookingTicket/index.d.ts +1 -1
  59. package/lib/solution/ScanOrder/index.js +4 -4
  60. package/lib/solution/ScanOrder/types.d.ts +8 -5
  61. package/lib/solution/ScanOrder/utils.d.ts +1 -1
  62. package/lib/solution/ScanOrder/utils.js +12 -8
  63. package/lib/solution/VenueBooking/index.js +2 -2
  64. package/lib/solution/VenueBooking/sales-section-4-annotated.json +0 -2
  65. package/package.json +1 -1
  66. package/dist/solution/Checkout/appointmentDemo.json +0 -1
  67. package/lib/solution/Checkout/appointmentDemo.json +0 -1
@@ -40,6 +40,15 @@ var INDEXDB_STORE_NAME = "orders";
40
40
  var ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY = "server_order_last_full_fetch_at";
41
41
  var ORDER_SYNC_THROTTLE_MS_STORAGE_KEY = "order_sync_throttle_ms";
42
42
  var DEFAULT_ORDER_SYNC_THROTTLE_MS = 2e3;
43
+ var ORDER_FLOW_LOG_WINDOW_KEY = "__orderModuleFlowLogs";
44
+ var ORDER_WRITE_STATS_WINDOW_KEY = "__orderModuleWriteStats";
45
+ var ORDER_FLOW_LOG_MAX_LENGTH = 1e3;
46
+ var ORDER_SQLITE_DEDUPE_MS = 15e3;
47
+ var ORDER_SILENT_REFRESH_MIN_INTERVAL_MS = 3e4;
48
+ var ORDER_BUSINESS_WRITE_SOURCES = /* @__PURE__ */ new Set([
49
+ "upsertOrdersFromRemote",
50
+ "overwriteExistingOrder"
51
+ ]);
43
52
  var OrderModule = class extends import_BaseModule.BaseModule {
44
53
  constructor(name, version) {
45
54
  super(name, version);
@@ -51,6 +60,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
51
60
  // Map<resource_id, OrderId[]> 资源到订单的倒排索引
52
61
  this.resourceIdIndex = /* @__PURE__ */ new Map();
53
62
  this.orderSQLiteSaveQueue = Promise.resolve();
63
+ /** 全局递增的 SQLite 写入序号,便于日志关联同一次操作 */
64
+ this.orderFlowWriteSeq = 0;
65
+ /** 按 storageKey 记录最近一次 SQLite 写入来源与时间,用于去重 */
66
+ this.recentSqliteWriteByStorageKey = /* @__PURE__ */ new Map();
67
+ /** 最近一次 SSE 全量拉取完成时间 */
68
+ this.lastServerFullFetchAtMs = 0;
54
69
  }
55
70
  async initialize(core, options) {
56
71
  var _a, _b;
@@ -113,8 +128,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
113
128
  this.store.list = [];
114
129
  this.store.map = /* @__PURE__ */ new Map();
115
130
  }
131
+ this.initOrderFlowLogs();
116
132
  this.initOrderDataSource();
117
133
  this.setupOrderSync();
134
+ this.pushOrderFlowLog("initialize.complete", {
135
+ hasDbManager: !!this.dbManager,
136
+ hasLogger: !!this.logger,
137
+ initialOrderCount: this.store.list.length,
138
+ createdAtQuery: this.store.createdAtQuery || null
139
+ });
118
140
  this.logInfo("OrderServer模块初始化完成", {
119
141
  hasDbManager: !!this.dbManager,
120
142
  hasLogger: !!this.logger,
@@ -154,6 +176,297 @@ var OrderModule = class extends import_BaseModule.BaseModule {
154
176
  }
155
177
  } catch {
156
178
  }
179
+ this.pushOrderFlowLog(`error.${title}`, metadata);
180
+ }
181
+ /**
182
+ * 初始化 window 上的订单流程调试日志数组及辅助方法。
183
+ *
184
+ * @example
185
+ * window.clearOrderModuleFlowLogs()
186
+ * // 操作完成后:
187
+ * copy(window.exportOrderModuleFlowLogs?.() || '[]')
188
+ */
189
+ initOrderFlowLogs() {
190
+ try {
191
+ const win = typeof globalThis !== "undefined" ? globalThis.window : void 0;
192
+ if (!win)
193
+ return;
194
+ win[ORDER_FLOW_LOG_WINDOW_KEY] = [];
195
+ win[ORDER_WRITE_STATS_WINDOW_KEY] = {};
196
+ win.clearOrderModuleFlowLogs = () => {
197
+ win[ORDER_FLOW_LOG_WINDOW_KEY] = [];
198
+ win[ORDER_WRITE_STATS_WINDOW_KEY] = {};
199
+ this.orderFlowWriteSeq = 0;
200
+ this.recentSqliteWriteByStorageKey.clear();
201
+ this.lastServerFullFetchAtMs = 0;
202
+ this.pushOrderFlowLog("debug.clear", {});
203
+ };
204
+ win.exportOrderModuleFlowLogs = () => {
205
+ const logs = win[ORDER_FLOW_LOG_WINDOW_KEY] || [];
206
+ return JSON.stringify(logs, null, 2);
207
+ };
208
+ win.exportOrderModuleWriteStats = () => {
209
+ const stats = win[ORDER_WRITE_STATS_WINDOW_KEY] || {};
210
+ return JSON.stringify(stats, null, 2);
211
+ };
212
+ win.summarizeOrderModuleWrites = (topN = 20) => {
213
+ const stats = win[ORDER_WRITE_STATS_WINDOW_KEY] || {};
214
+ return Object.entries(stats).map(([storageKey, entries]) => {
215
+ const list = entries || [];
216
+ const sources = [...new Set(list.map((item) => item.source))];
217
+ const last = list[list.length - 1];
218
+ return {
219
+ storageKey,
220
+ orderId: (last == null ? void 0 : last.orderId) ?? null,
221
+ writeCount: list.length,
222
+ sources,
223
+ lastWriteAt: (last == null ? void 0 : last.ts) || ""
224
+ };
225
+ }).sort((a, b) => b.writeCount - a.writeCount).slice(0, topN);
226
+ };
227
+ this.pushOrderFlowLog("debug.init", {
228
+ logKey: ORDER_FLOW_LOG_WINDOW_KEY,
229
+ writeStatsKey: ORDER_WRITE_STATS_WINDOW_KEY,
230
+ helpers: [
231
+ "clearOrderModuleFlowLogs",
232
+ "exportOrderModuleFlowLogs",
233
+ "exportOrderModuleWriteStats",
234
+ "summarizeOrderModuleWrites"
235
+ ]
236
+ });
237
+ } catch {
238
+ }
239
+ }
240
+ /**
241
+ * 写入 window 订单流程调试日志。
242
+ *
243
+ * @example
244
+ * this.pushOrderFlowLog('mergeOrdersToStore.start', { count: 3 })
245
+ */
246
+ pushOrderFlowLog(step, metadata) {
247
+ try {
248
+ const win = typeof globalThis !== "undefined" ? globalThis.window : void 0;
249
+ if (!win)
250
+ return;
251
+ if (!Array.isArray(win[ORDER_FLOW_LOG_WINDOW_KEY])) {
252
+ win[ORDER_FLOW_LOG_WINDOW_KEY] = [];
253
+ }
254
+ const entry = {
255
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
256
+ step,
257
+ metadata: metadata || {}
258
+ };
259
+ win[ORDER_FLOW_LOG_WINDOW_KEY].push(entry);
260
+ const logs = win[ORDER_FLOW_LOG_WINDOW_KEY];
261
+ if (logs.length > ORDER_FLOW_LOG_MAX_LENGTH) {
262
+ logs.splice(0, logs.length - ORDER_FLOW_LOG_MAX_LENGTH);
263
+ }
264
+ console.log(`[OrderFlow] ${step}`, metadata || {});
265
+ } catch {
266
+ }
267
+ }
268
+ /** 当前内存 store 快照信息,供流程日志使用 */
269
+ getOrderStoreSnapshot() {
270
+ return {
271
+ storeListCount: this.store.list.length,
272
+ storeMapCount: this.store.map.size,
273
+ pendingSyncCount: this.pendingSyncMessages.length,
274
+ isProcessingSyncBatch: this.isProcessingSyncBatch,
275
+ isIdlePhase: this.isIdlePhase
276
+ };
277
+ }
278
+ /**
279
+ * 记录一次 SQLite 写入到 window 统计,用于排查同一订单被多次写入的原因。
280
+ *
281
+ * @example
282
+ * this.trackOrderWrite('upsertOrdersFromRemote', 'bulkUpdate', orders, 'insert')
283
+ */
284
+ trackOrderWrite(source, writeMethod, orders, mergeActions = {}, defaultMergeAction = "update") {
285
+ this.orderFlowWriteSeq += 1;
286
+ const writeSeq = this.orderFlowWriteSeq;
287
+ try {
288
+ const win = typeof globalThis !== "undefined" ? globalThis.window : void 0;
289
+ if (!win)
290
+ return writeSeq;
291
+ if (!win[ORDER_WRITE_STATS_WINDOW_KEY]) {
292
+ win[ORDER_WRITE_STATS_WINDOW_KEY] = {};
293
+ }
294
+ const stats = win[ORDER_WRITE_STATS_WINDOW_KEY];
295
+ for (const order of orders) {
296
+ const storageKey = this.getOrderStorageKey(order);
297
+ if (!storageKey)
298
+ continue;
299
+ const orderKey = order.order_id !== void 0 && order.order_id !== null ? this.getIdKey(order.order_id) : "";
300
+ const mergeAction = orderKey && mergeActions[orderKey] || defaultMergeAction;
301
+ const entry = {
302
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
303
+ writeSeq,
304
+ source,
305
+ writeMethod,
306
+ orderId: order.order_id ?? null,
307
+ storageKey,
308
+ mergeAction
309
+ };
310
+ if (!stats[storageKey])
311
+ stats[storageKey] = [];
312
+ stats[storageKey].push(entry);
313
+ }
314
+ } catch {
315
+ }
316
+ return writeSeq;
317
+ }
318
+ /**
319
+ * 记录订单最近一次 SQLite 写入,供 pubsub 回声去重使用。
320
+ *
321
+ * @example
322
+ * this.recordRecentSqliteWrite('upsertOrdersFromRemote', orders)
323
+ */
324
+ recordRecentSqliteWrite(source, orders) {
325
+ const now = Date.now();
326
+ for (const order of orders) {
327
+ const storageKey = this.getOrderStorageKey(order);
328
+ if (!storageKey)
329
+ continue;
330
+ this.recentSqliteWriteByStorageKey.set(storageKey, { source, ts: now });
331
+ }
332
+ }
333
+ /**
334
+ * 过滤 pubsub 触发的冗余 SQLite patch(业务 API 刚写入过的 update 回声)。
335
+ *
336
+ * @example
337
+ * const { toWrite, skipped } = this.filterRedundantPatchOrders('pubsub.bodyUpsert', orders, mergeActions)
338
+ */
339
+ filterRedundantPatchOrders(source, orders, mergeActions) {
340
+ const eligibleSkipSources = /* @__PURE__ */ new Set(["pubsub.bodyUpsert", "pubsub.httpRefresh"]);
341
+ if (!eligibleSkipSources.has(source)) {
342
+ return { toWrite: orders, skipped: [] };
343
+ }
344
+ const now = Date.now();
345
+ const toWrite = [];
346
+ const skipped = [];
347
+ for (const order of orders) {
348
+ const storageKey = this.getOrderStorageKey(order);
349
+ if (!storageKey) {
350
+ toWrite.push(order);
351
+ continue;
352
+ }
353
+ const orderKey = order.order_id !== void 0 && order.order_id !== null ? this.getIdKey(order.order_id) : "";
354
+ const mergeAction = orderKey ? mergeActions[orderKey] : void 0;
355
+ if (mergeAction === "insert") {
356
+ toWrite.push(order);
357
+ continue;
358
+ }
359
+ const recent = this.recentSqliteWriteByStorageKey.get(storageKey);
360
+ if (recent && ORDER_BUSINESS_WRITE_SOURCES.has(recent.source) && now - recent.ts < ORDER_SQLITE_DEDUPE_MS) {
361
+ skipped.push({
362
+ orderId: order.order_id ?? null,
363
+ storageKey,
364
+ reason: "skip_pubsub_echo_after_business_write",
365
+ lastSource: recent.source,
366
+ elapsedMs: now - recent.ts
367
+ });
368
+ continue;
369
+ }
370
+ toWrite.push(order);
371
+ }
372
+ return { toWrite, skipped };
373
+ }
374
+ /**
375
+ * 过滤 pubsub HTTP 增量拉取 ids:本地刚由业务 API 写入的单可跳过 HTTP。
376
+ *
377
+ * @example
378
+ * const ids = this.filterRedundantHttpRefreshIds([99331, 99332])
379
+ */
380
+ filterRedundantHttpRefreshIds(ids) {
381
+ const now = Date.now();
382
+ const toFetch = [];
383
+ const skipped = [];
384
+ for (const id of ids) {
385
+ const existing = this.getOrderByOrderId(id);
386
+ if (!existing) {
387
+ toFetch.push(id);
388
+ continue;
389
+ }
390
+ const storageKey = this.getOrderStorageKey(existing);
391
+ const recent = storageKey ? this.recentSqliteWriteByStorageKey.get(storageKey) : void 0;
392
+ if (recent && recent.source === "upsertOrdersFromRemote" && now - recent.ts < ORDER_SQLITE_DEDUPE_MS) {
393
+ skipped.push({
394
+ orderId: id,
395
+ lastSource: recent.source,
396
+ elapsedMs: now - recent.ts
397
+ });
398
+ continue;
399
+ }
400
+ toFetch.push(id);
401
+ }
402
+ return { toFetch, skipped };
403
+ }
404
+ /**
405
+ * 解析 pubsub 消息会走哪条同步分支,便于对照为何触发 HTTP 重拉或 body 直写。
406
+ *
407
+ * @example
408
+ * this.resolveSyncMessageRoute(msg)
409
+ * // => { route: 'httpRefresh.batchIds', ... }
410
+ */
411
+ resolveSyncMessageRoute(msg) {
412
+ var _a;
413
+ const hasBatchIds = Array.isArray(msg.ids) && msg.ids.length > 0;
414
+ const singleIdRaw = msg.id ?? msg.order_id;
415
+ const hasSingleId = !hasBatchIds && singleIdRaw !== void 0 && singleIdRaw !== null;
416
+ const normalizedBody = this.normalizeOrderSyncPayload(msg.body || msg.data);
417
+ if (hasBatchIds) {
418
+ return {
419
+ route: "httpRefresh.batchIds",
420
+ hasBatchIds: true,
421
+ hasSingleId: false,
422
+ hasNormalizedBody: !!normalizedBody,
423
+ singleId: null,
424
+ batchIds: msg.ids || [],
425
+ bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
426
+ };
427
+ }
428
+ if (hasSingleId && normalizedBody) {
429
+ return {
430
+ route: "bodyUpsert",
431
+ hasBatchIds: false,
432
+ hasSingleId: true,
433
+ hasNormalizedBody: true,
434
+ singleId: singleIdRaw,
435
+ batchIds: [],
436
+ bodyOrderId: normalizedBody.order_id ?? null
437
+ };
438
+ }
439
+ if (hasSingleId) {
440
+ return {
441
+ route: "httpRefresh.singleId",
442
+ hasBatchIds: false,
443
+ hasSingleId: true,
444
+ hasNormalizedBody: !!normalizedBody,
445
+ singleId: singleIdRaw,
446
+ batchIds: [],
447
+ bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
448
+ };
449
+ }
450
+ if ((_a = msg.relation_order_ids) == null ? void 0 : _a.length) {
451
+ return {
452
+ route: "httpRefresh.relationIds",
453
+ hasBatchIds: false,
454
+ hasSingleId: false,
455
+ hasNormalizedBody: !!normalizedBody,
456
+ singleId: null,
457
+ batchIds: msg.relation_order_ids,
458
+ bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
459
+ };
460
+ }
461
+ return {
462
+ route: "noop",
463
+ hasBatchIds: false,
464
+ hasSingleId: false,
465
+ hasNormalizedBody: !!normalizedBody,
466
+ singleId: null,
467
+ batchIds: [],
468
+ bodyOrderId: (normalizedBody == null ? void 0 : normalizedBody.order_id) ?? null
469
+ };
157
470
  }
158
471
  getOrderSyncThrottleMs() {
159
472
  const raw = localStorage.getItem(ORDER_SYNC_THROTTLE_MS_STORAGE_KEY);
@@ -165,14 +478,21 @@ var OrderModule = class extends import_BaseModule.BaseModule {
165
478
  return DEFAULT_ORDER_SYNC_THROTTLE_MS;
166
479
  }
167
480
  async preload() {
481
+ this.pushOrderFlowLog("preload.start", this.getOrderStoreSnapshot());
168
482
  const getData = async () => {
169
483
  const orders = await this.loadOrdersByServer();
170
- if (orders.length === 0)
484
+ if (orders.length === 0) {
485
+ this.pushOrderFlowLog("preload.empty", this.getOrderStoreSnapshot());
171
486
  return;
487
+ }
172
488
  this.store.list = (0, import_lodash_es.cloneDeep)(orders);
173
489
  this.syncOrdersMap();
174
490
  this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, this.store.list);
175
491
  this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
492
+ this.pushOrderFlowLog("preload.done", {
493
+ ...this.getOrderStoreSnapshot(),
494
+ loadedCount: orders.length
495
+ });
176
496
  };
177
497
  getData();
178
498
  }
@@ -189,8 +509,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
189
509
  async getLocalOrderByOrderId(orderId) {
190
510
  const key = this.getIdKey(orderId);
191
511
  const memoryOrder = this.store.map.get(key);
192
- if (memoryOrder)
512
+ if (memoryOrder) {
513
+ this.pushOrderFlowLog("getLocalOrderByOrderId.hitMemory", { orderId, key });
193
514
  return memoryOrder;
515
+ }
516
+ this.pushOrderFlowLog("getLocalOrderByOrderId.missMemory", { orderId, key });
194
517
  const orders = await this.loadOrdersFromSQLite();
195
518
  const localOrder = orders.find((order) => {
196
519
  const shopOrderNumber = order == null ? void 0 : order.shop_order_number;
@@ -208,11 +531,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
208
531
  return localOrder;
209
532
  }
210
533
  async loadOrdersByServer() {
211
- var _a;
534
+ var _a, _b;
212
535
  let orderList = [];
536
+ this.pushOrderFlowLog("loadOrdersByServer.start", {
537
+ ...this.getOrderStoreSnapshot(),
538
+ query: ((_a = this.store) == null ? void 0 : _a.createdAtQuery) || null,
539
+ hasOrderDataSource: !!this.orderDataSource
540
+ });
213
541
  this.logInfo("loadOrdersByServer-开始", {
214
542
  hasOrderDataSource: !!this.orderDataSource,
215
- query: ((_a = this.store) == null ? void 0 : _a.createdAtQuery) || null
543
+ query: ((_b = this.store) == null ? void 0 : _b.createdAtQuery) || null
216
544
  });
217
545
  if (this.orderDataSource) {
218
546
  try {
@@ -222,16 +550,23 @@ var OrderModule = class extends import_BaseModule.BaseModule {
222
550
  }
223
551
  });
224
552
  orderList = data || [];
553
+ this.pushOrderFlowLog("loadOrdersByServer.sseSuccess", { count: orderList.length });
225
554
  this.logInfo("loadOrdersByServer-SSE拉取成功", {
226
555
  count: orderList.length
227
556
  });
228
557
  this.markOrderPulledAtNow();
558
+ this.lastServerFullFetchAtMs = Date.now();
229
559
  } catch {
230
560
  orderList = [];
561
+ this.pushOrderFlowLog("loadOrdersByServer.sseFailed", {});
231
562
  this.logInfo("loadOrdersByServer-SSE拉取失败,回退为空数组");
232
563
  }
233
564
  }
234
- await this.saveOrdersToSQLite(orderList);
565
+ await this.replaceOrdersSnapshotInSQLite(orderList, "loadOrdersByServer");
566
+ this.pushOrderFlowLog("loadOrdersByServer.done", {
567
+ count: orderList.length,
568
+ ...this.getOrderStoreSnapshot()
569
+ });
235
570
  this.logInfo("loadOrdersByServer-结束", {
236
571
  count: orderList.length
237
572
  });
@@ -245,6 +580,19 @@ var OrderModule = class extends import_BaseModule.BaseModule {
245
580
  */
246
581
  async silentRefresh() {
247
582
  const startTime = Date.now();
583
+ const elapsedSinceFullFetch = Date.now() - this.lastServerFullFetchAtMs;
584
+ if (this.lastServerFullFetchAtMs > 0 && elapsedSinceFullFetch < ORDER_SILENT_REFRESH_MIN_INTERVAL_MS) {
585
+ this.pushOrderFlowLog("silentRefresh.skipped", {
586
+ elapsedMs: elapsedSinceFullFetch,
587
+ minIntervalMs: ORDER_SILENT_REFRESH_MIN_INTERVAL_MS,
588
+ ...this.getOrderStoreSnapshot()
589
+ });
590
+ return this.store.list;
591
+ }
592
+ this.pushOrderFlowLog("silentRefresh.start", {
593
+ ...this.getOrderStoreSnapshot(),
594
+ callerHint: "Server.refreshOrdersInBackground 或其他调用方"
595
+ });
248
596
  this.logInfo("silentRefresh 开始");
249
597
  try {
250
598
  const orders = await this.loadOrdersByServer();
@@ -253,11 +601,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
253
601
  this.syncOrdersMap();
254
602
  this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, this.store.list);
255
603
  await this.core.effects.emit(import_types.OrderHooks.onOrdersSyncCompleted, null);
604
+ this.pushOrderFlowLog("silentRefresh.done", {
605
+ orderCount: orders.length,
606
+ durationMs: Date.now() - startTime,
607
+ ...this.getOrderStoreSnapshot()
608
+ });
256
609
  this.logInfo("silentRefresh 完成", {
257
610
  orderCount: orders.length,
258
611
  duration: `${Date.now() - startTime}ms`
259
612
  });
260
613
  } else {
614
+ this.pushOrderFlowLog("silentRefresh.empty", { durationMs: Date.now() - startTime });
261
615
  this.logInfo("silentRefresh: 服务器未返回数据");
262
616
  }
263
617
  return this.store.list;
@@ -289,6 +643,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
289
643
  this.logInfo("overwriteExistingOrder-本地不存在该订单,跳过", { orderId });
290
644
  return { overwritten: false };
291
645
  }
646
+ this.pushOrderFlowLog("overwriteExistingOrder.start", {
647
+ orderId,
648
+ storageKey: this.getOrderStorageKey(fresh),
649
+ ...this.getOrderStoreSnapshot(),
650
+ callerHint: "Server.handleUpdateLocalOrder 本地已存在时"
651
+ });
292
652
  this.logInfo("overwriteExistingOrder-开始覆盖", {
293
653
  orderId,
294
654
  storeOrderCountBefore: this.store.list.length
@@ -300,7 +660,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
300
660
  return this.getIdKey(id) === key ? fresh : order;
301
661
  });
302
662
  this.syncOrdersMap();
303
- await this.saveOrdersToSQLite(this.store.list);
663
+ await this.updateOrderInSQLite(fresh, "overwriteExistingOrder");
664
+ this.pushOrderFlowLog("overwriteExistingOrder.done", {
665
+ orderId,
666
+ ...this.getOrderStoreSnapshot()
667
+ });
304
668
  this.logInfo("overwriteExistingOrder-结束", {
305
669
  orderId,
306
670
  storeOrderCountAfter: this.store.list.length
@@ -317,8 +681,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
317
681
  this.logInfo("upsertOrdersFromRemote-订单列表为空", {});
318
682
  return;
319
683
  }
684
+ this.pushOrderFlowLog("upsertOrdersFromRemote.start", {
685
+ count: freshOrders.length,
686
+ orderIds: freshOrders.map((o) => o.order_id).filter((id) => id !== void 0 && id !== null),
687
+ callerHint: "Server.handleUpdateLocalOrder / handleOrderSalesDetail / handleUpdateLocalOrdersBatch"
688
+ });
320
689
  this.logInfo("upsertOrdersFromRemote-开始", { count: freshOrders.length });
321
- await this.mergeOrdersToStore(freshOrders);
690
+ await this.mergeOrdersToStore(freshOrders, "upsertOrdersFromRemote");
322
691
  }
323
692
  /**
324
693
  * 通过 SSE 按自定义 query 拉取订单(支持 select/with 精简字段)
@@ -426,7 +795,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
426
795
  this.orderDataSource.run({
427
796
  pubsub: {
428
797
  callback: (res) => {
429
- console.log("orderDataSource");
798
+ console.log("orderDataSource", res);
430
799
  const pubsubReceivedAt = Date.now();
431
800
  const message = this.normalizeOrderSyncMessage(res);
432
801
  if (!message)
@@ -434,6 +803,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
434
803
  message._pubsubReceivedAt = pubsubReceivedAt;
435
804
  this.pendingSyncMessages.push(message);
436
805
  const throttleMs = this.getOrderSyncThrottleMs();
806
+ const routeInfo = this.resolveSyncMessageRoute(message);
807
+ this.pushOrderFlowLog("orderSync.received", {
808
+ id: message.id ?? null,
809
+ order_id: message.order_id ?? null,
810
+ type: message.type ?? null,
811
+ pendingCount: this.pendingSyncMessages.length,
812
+ throttleMs,
813
+ ...routeInfo,
814
+ duplicateRiskHint: routeInfo.route === "httpRefresh.batchIds" && routeInfo.hasNormalizedBody ? "有 body 但被 ids 优先,会走 HTTP 重拉" : routeInfo.route === "bodyUpsert" ? "body 直写,可能与 upsertOrdersFromRemote 重复" : null
815
+ });
437
816
  this.logInfo("orderSync-收到消息并入队", {
438
817
  id: message.id ?? null,
439
818
  order_id: message.order_id ?? null,
@@ -459,6 +838,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
459
838
  return;
460
839
  if (this.isIdlePhase) {
461
840
  this.isIdlePhase = false;
841
+ this.pushOrderFlowLog("orderSync.flushImmediate", {
842
+ pendingCount: this.pendingSyncMessages.length
843
+ });
462
844
  this.logInfo("orderSync-首条消息立即触发处理");
463
845
  void this.flushOrderSyncMessagesByThrottle();
464
846
  return;
@@ -466,6 +848,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
466
848
  if (this.syncTimer)
467
849
  return;
468
850
  const throttleMs = this.getOrderSyncThrottleMs();
851
+ this.pushOrderFlowLog("orderSync.flushScheduled", {
852
+ pendingCount: this.pendingSyncMessages.length,
853
+ throttleMs
854
+ });
469
855
  this.syncTimer = setTimeout(() => {
470
856
  this.syncTimer = void 0;
471
857
  void this.flushOrderSyncMessagesByThrottle();
@@ -483,6 +869,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
483
869
  return;
484
870
  }
485
871
  this.isProcessingSyncBatch = true;
872
+ this.pushOrderFlowLog("orderSync.flushStart", {
873
+ pendingCount: this.pendingSyncMessages.length
874
+ });
486
875
  try {
487
876
  await this.processOrderSyncMessages();
488
877
  } finally {
@@ -506,12 +895,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
506
895
  * await this.processOrderSyncMessages()
507
896
  */
508
897
  async processOrderSyncMessages() {
509
- var _a;
510
898
  const messages = [...this.pendingSyncMessages];
511
899
  this.pendingSyncMessages = [];
512
900
  if (messages.length === 0)
513
901
  return;
514
902
  const batchProcessStartAt = Date.now();
903
+ this.pushOrderFlowLog("processOrderSyncMessages.start", {
904
+ messageCount: messages.length,
905
+ ...this.getOrderStoreSnapshot()
906
+ });
515
907
  const earliestReceivedAt = Math.min(
516
908
  ...messages.map((m) => m._pubsubReceivedAt ?? batchProcessStartAt)
517
909
  );
@@ -523,39 +915,74 @@ var OrderModule = class extends import_BaseModule.BaseModule {
523
915
  });
524
916
  const upsertOrders = /* @__PURE__ */ new Map();
525
917
  const refreshIds = [];
526
- for (const msg of messages) {
527
- const hasBatchIds = Array.isArray(msg.ids) && msg.ids.length > 0;
528
- const singleId = msg.id ?? msg.order_id;
529
- const hasSingleId = !hasBatchIds && singleId !== void 0 && singleId !== null;
530
- const rawBody = msg.body || msg.data;
531
- const normalizedBody = this.normalizeOrderSyncPayload(rawBody);
532
- if (hasSingleId && normalizedBody) {
918
+ messages.forEach((msg, msgIndex) => {
919
+ const routeInfo = this.resolveSyncMessageRoute(msg);
920
+ this.pushOrderFlowLog("processOrderSyncMessages.messageRoute", {
921
+ msgIndex,
922
+ ...routeInfo
923
+ });
924
+ const hasBatchIds = routeInfo.hasBatchIds;
925
+ const singleId = routeInfo.singleId;
926
+ const hasSingleId = routeInfo.hasSingleId;
927
+ const normalizedBody = this.normalizeOrderSyncPayload(msg.body || msg.data);
928
+ if (routeInfo.route === "bodyUpsert" && normalizedBody) {
533
929
  upsertOrders.set(this.getIdKey(normalizedBody.order_id), normalizedBody);
534
- continue;
930
+ return;
535
931
  }
536
932
  if (hasBatchIds)
537
- refreshIds.push(...msg.ids);
538
- else if (hasSingleId)
933
+ refreshIds.push(...routeInfo.batchIds);
934
+ else if (routeInfo.route === "httpRefresh.singleId" && singleId !== null)
539
935
  refreshIds.push(singleId);
540
- else if ((_a = msg.relation_order_ids) == null ? void 0 : _a.length)
541
- refreshIds.push(...msg.relation_order_ids);
542
- }
936
+ else if (routeInfo.route === "httpRefresh.relationIds")
937
+ refreshIds.push(...routeInfo.batchIds);
938
+ });
543
939
  const uniqueRefreshIds = this.uniqueOrderIds(refreshIds);
544
940
  const upsertList = [...upsertOrders.values()];
941
+ this.pushOrderFlowLog("processOrderSyncMessages.deduped", {
942
+ upsertCount: upsertList.length,
943
+ upsertOrderIds: upsertList.map((o) => o.order_id),
944
+ refreshIdCount: uniqueRefreshIds.length,
945
+ refreshIds: uniqueRefreshIds,
946
+ willCallMergeTimes: (upsertList.length > 0 ? 1 : 0) + (uniqueRefreshIds.length > 0 ? 1 : 0)
947
+ });
545
948
  this.logInfo("processOrderSyncMessages-去重完成", {
546
949
  upsertCount: upsertList.length,
547
950
  refreshIdCount: uniqueRefreshIds.length
548
951
  });
549
- if (upsertList.length > 0)
550
- await this.mergeOrdersToStore(upsertList);
952
+ if (upsertList.length > 0) {
953
+ await this.mergeOrdersToStore(upsertList, "pubsub.bodyUpsert");
954
+ }
551
955
  if (uniqueRefreshIds.length > 0) {
552
- const freshOrders = await this.fetchOrdersByHttp(uniqueRefreshIds);
553
- if (freshOrders.length > 0)
554
- await this.mergeOrdersToStore(freshOrders);
956
+ const { toFetch, skipped } = this.filterRedundantHttpRefreshIds(uniqueRefreshIds);
957
+ if (skipped.length > 0) {
958
+ this.pushOrderFlowLog("processOrderSyncMessages.httpRefreshFiltered", {
959
+ requestedIds: uniqueRefreshIds,
960
+ skippedIds: skipped.map((item) => item.orderId),
961
+ skipped
962
+ });
963
+ }
964
+ if (toFetch.length > 0) {
965
+ const freshOrders = await this.fetchOrdersByHttp(toFetch);
966
+ if (freshOrders.length > 0) {
967
+ await this.mergeOrdersToStore(freshOrders, "pubsub.httpRefresh");
968
+ } else {
969
+ this.pushOrderFlowLog("processOrderSyncMessages.httpRefreshEmpty", {
970
+ refreshIds: toFetch
971
+ });
972
+ }
973
+ }
555
974
  }
556
- if (upsertList.length === 0 && uniqueRefreshIds.length === 0)
975
+ if (upsertList.length === 0 && uniqueRefreshIds.length === 0) {
976
+ this.pushOrderFlowLog("processOrderSyncMessages.noop", {});
557
977
  return;
978
+ }
558
979
  const batchProcessEndAt = Date.now();
980
+ this.pushOrderFlowLog("processOrderSyncMessages.done", {
981
+ upsertCount: upsertList.length,
982
+ refreshIdCount: uniqueRefreshIds.length,
983
+ batchProcessDurationMs: batchProcessEndAt - batchProcessStartAt,
984
+ ...this.getOrderStoreSnapshot()
985
+ });
559
986
  this.logInfo("processOrderSyncMessages-结束", {
560
987
  upsertCount: upsertList.length,
561
988
  refreshIdCount: uniqueRefreshIds.length,
@@ -577,9 +1004,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
577
1004
  async fetchOrdersByHttp(ids) {
578
1005
  if (!this.orderDataSource || ids.length === 0)
579
1006
  return [];
1007
+ this.pushOrderFlowLog("fetchOrdersByHttp.start", { ids, count: ids.length });
580
1008
  try {
581
1009
  if (typeof this.orderDataSource.fetchOrdersByIds === "function") {
582
1010
  const orderList2 = await this.orderDataSource.fetchOrdersByIds(ids);
1011
+ this.pushOrderFlowLog("fetchOrdersByHttp.done", {
1012
+ ids,
1013
+ count: (orderList2 == null ? void 0 : orderList2.length) || 0,
1014
+ via: "fetchOrdersByIds"
1015
+ });
583
1016
  return orderList2 || [];
584
1017
  }
585
1018
  const orderList = await this.orderDataSource.run({
@@ -587,15 +1020,27 @@ var OrderModule = class extends import_BaseModule.BaseModule {
587
1020
  query: { ids }
588
1021
  }
589
1022
  });
1023
+ this.pushOrderFlowLog("fetchOrdersByHttp.done", {
1024
+ ids,
1025
+ count: (orderList == null ? void 0 : orderList.length) || 0,
1026
+ via: "run.http"
1027
+ });
590
1028
  return orderList || [];
591
1029
  } catch {
1030
+ this.pushOrderFlowLog("fetchOrdersByHttp.failed", { ids });
592
1031
  return [];
593
1032
  }
594
1033
  }
595
1034
  /**
596
1035
  * 将增量订单合并到 store
597
1036
  */
598
- async mergeOrdersToStore(freshOrders) {
1037
+ async mergeOrdersToStore(freshOrders, source) {
1038
+ this.pushOrderFlowLog("mergeOrdersToStore.start", {
1039
+ source,
1040
+ freshOrderCount: freshOrders.length,
1041
+ freshOrderIds: freshOrders.map((o) => o.order_id).filter((id) => id !== void 0 && id !== null),
1042
+ ...this.getOrderStoreSnapshot()
1043
+ });
599
1044
  this.logInfo("mergeOrdersToStore-开始", {
600
1045
  freshOrderCount: freshOrders.length,
601
1046
  storeOrderCountBefore: this.store.list.length
@@ -608,6 +1053,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
608
1053
  freshMap.set(this.getIdKey(id), order);
609
1054
  }
610
1055
  const uniqueFreshCount = freshMap.size;
1056
+ const patchedOrders = [...freshMap.values()];
1057
+ const mergeActions = {};
611
1058
  const updatedList = this.store.list.map((order) => {
612
1059
  const id = order.order_id;
613
1060
  if (id === void 0 || id === null)
@@ -617,14 +1064,32 @@ var OrderModule = class extends import_BaseModule.BaseModule {
617
1064
  return order;
618
1065
  const fresh = freshMap.get(key);
619
1066
  freshMap.delete(key);
1067
+ mergeActions[key] = "update";
620
1068
  return fresh;
621
1069
  });
622
1070
  for (const order of freshMap.values()) {
1071
+ const id = order.order_id;
1072
+ if (id !== void 0 && id !== null) {
1073
+ mergeActions[this.getIdKey(id)] = "insert";
1074
+ }
623
1075
  updatedList.push(order);
624
1076
  }
1077
+ const insertCount = Object.values(mergeActions).filter((v) => v === "insert").length;
1078
+ const updateCount = Object.values(mergeActions).filter((v) => v === "update").length;
625
1079
  this.store.list = updatedList;
626
1080
  this.syncOrdersMap();
627
- await this.saveOrdersToSQLite(this.store.list);
1081
+ await this.patchOrdersInSQLite(patchedOrders, source, mergeActions);
1082
+ this.pushOrderFlowLog("mergeOrdersToStore.done", {
1083
+ source,
1084
+ uniqueFreshCount,
1085
+ insertCount,
1086
+ updateCount,
1087
+ patchedCount: patchedOrders.length,
1088
+ patchedOrderIds: patchedOrders.map((o) => o.order_id),
1089
+ patchedStorageKeys: patchedOrders.map((o) => this.getOrderStorageKey(o)),
1090
+ mergeActions,
1091
+ ...this.getOrderStoreSnapshot()
1092
+ });
628
1093
  this.logInfo("mergeOrdersToStore-结束", {
629
1094
  uniqueFreshCount,
630
1095
  storeOrderCountAfter: this.store.list.length
@@ -674,6 +1139,24 @@ var OrderModule = class extends import_BaseModule.BaseModule {
674
1139
  getIdKey(id) {
675
1140
  return String(id);
676
1141
  }
1142
+ /**
1143
+ * 解析订单 SQLite 主键,规则与宿主 OrderDataSource.getOrderStorageKey 一致。
1144
+ *
1145
+ * @example
1146
+ * const key = this.getOrderStorageKey({ order_id: 1001, external_sale_number: 'S-1001' })
1147
+ * // => 'S-1001'
1148
+ */
1149
+ getOrderStorageKey(order) {
1150
+ const externalSaleNumber = order == null ? void 0 : order.external_sale_number;
1151
+ if (externalSaleNumber !== void 0 && externalSaleNumber !== null && externalSaleNumber !== "") {
1152
+ return String(externalSaleNumber);
1153
+ }
1154
+ const orderId = order == null ? void 0 : order.order_id;
1155
+ if (orderId !== void 0 && orderId !== null && orderId !== "") {
1156
+ return String(orderId);
1157
+ }
1158
+ return "";
1159
+ }
677
1160
  /**
678
1161
  * 当前订单拉取窗口:
679
1162
  * - 优先使用 createdAtQuery.sales_time_between(已按营业日边界初始化)
@@ -745,12 +1228,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
745
1228
  }
746
1229
  }
747
1230
  /**
748
- * 串行执行订单 SQLite 保存任务,保证 clear + bulkAdd 组合不会被其它订单保存插入。
1231
+ * 串行执行订单 SQLite 写入任务,避免快照替换与增量 upsert 并发交错。
749
1232
  *
750
1233
  * @example
751
1234
  * await this.runInOrderSQLiteSaveQueue(async () => {
752
- * await this.dbManager.clear(INDEXDB_STORE_NAME)
753
- * await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, orders)
1235
+ * await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, orders)
754
1236
  * })
755
1237
  */
756
1238
  async runInOrderSQLiteSaveQueue(task) {
@@ -759,33 +1241,231 @@ var OrderModule = class extends import_BaseModule.BaseModule {
759
1241
  return queuedTask;
760
1242
  }
761
1243
  /**
762
- * 保存订单列表到 SQLite,内部会先清空 orders 表再批量写入当前快照。
1244
+ * 批量增量 upsert 订单到 SQLite,不清空表;用于 pubsub / HTTP 增量合并。
763
1245
  *
764
1246
  * @example
765
- * await this.saveOrdersToSQLite(this.store.list)
1247
+ * await this.patchOrdersInSQLite(freshOrders)
766
1248
  */
767
- async saveOrdersToSQLite(orderList) {
768
- if (!this.dbManager)
1249
+ async patchOrdersInSQLite(orders, source, mergeActions = {}) {
1250
+ if (!this.dbManager || orders.length === 0) {
1251
+ this.pushOrderFlowLog("patchOrdersInSQLite.skip", {
1252
+ source,
1253
+ hasDbManager: !!this.dbManager,
1254
+ inputCount: orders.length
1255
+ });
1256
+ return;
1257
+ }
1258
+ const ordersSnapshot = (0, import_lodash_es.cloneDeep)(orders).filter((order) => this.getOrderStorageKey(order));
1259
+ if (ordersSnapshot.length === 0) {
1260
+ this.pushOrderFlowLog("patchOrdersInSQLite.skipNoStorageKey", {
1261
+ source,
1262
+ inputCount: orders.length
1263
+ });
1264
+ return;
1265
+ }
1266
+ const { toWrite, skipped } = this.filterRedundantPatchOrders(
1267
+ source,
1268
+ ordersSnapshot,
1269
+ mergeActions
1270
+ );
1271
+ if (skipped.length > 0) {
1272
+ this.pushOrderFlowLog("patchOrdersInSQLite.dedupeSkipped", {
1273
+ source,
1274
+ skippedCount: skipped.length,
1275
+ skipped
1276
+ });
1277
+ }
1278
+ if (toWrite.length === 0) {
1279
+ this.pushOrderFlowLog("patchOrdersInSQLite.skipAllDeduped", {
1280
+ source,
1281
+ inputCount: ordersSnapshot.length,
1282
+ skipped
1283
+ });
1284
+ return;
1285
+ }
1286
+ try {
1287
+ await this.runInOrderSQLiteSaveQueue(async () => {
1288
+ let writeMethod = "none";
1289
+ this.pushOrderFlowLog("patchOrdersInSQLite.start", {
1290
+ source,
1291
+ count: toWrite.length,
1292
+ orderIds: toWrite.map((o) => o.order_id),
1293
+ storageKeys: toWrite.map((o) => this.getOrderStorageKey(o)),
1294
+ dedupedCount: skipped.length
1295
+ });
1296
+ this.logInfo("patchOrdersInSQLite-开始", {
1297
+ source,
1298
+ count: toWrite.length
1299
+ });
1300
+ if (typeof this.dbManager.bulkUpdate === "function") {
1301
+ writeMethod = "bulkUpdate";
1302
+ await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, toWrite);
1303
+ } else if (typeof this.dbManager.bulkAdd === "function") {
1304
+ writeMethod = "bulkAdd";
1305
+ await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, toWrite);
1306
+ } else if (typeof this.dbManager.update === "function") {
1307
+ writeMethod = "update";
1308
+ for (const order of toWrite) {
1309
+ await this.dbManager.update(INDEXDB_STORE_NAME, order);
1310
+ }
1311
+ }
1312
+ const writeSeq = this.trackOrderWrite(source, writeMethod, toWrite, mergeActions);
1313
+ this.recordRecentSqliteWrite(source, toWrite);
1314
+ this.pushOrderFlowLog("patchOrdersInSQLite.done", {
1315
+ source,
1316
+ writeSeq,
1317
+ count: toWrite.length,
1318
+ writeMethod,
1319
+ dedupedCount: skipped.length
1320
+ });
1321
+ this.logInfo("patchOrdersInSQLite-完成", {
1322
+ source,
1323
+ count: toWrite.length,
1324
+ dedupedCount: skipped.length
1325
+ });
1326
+ });
1327
+ } catch (error) {
1328
+ this.pushOrderFlowLog("patchOrdersInSQLite.error", {
1329
+ source,
1330
+ error: error instanceof Error ? error.message : String(error),
1331
+ orderCount: ordersSnapshot.length
1332
+ });
1333
+ this.logError("增量保存订单到 SQLite 失败", {
1334
+ error: error instanceof Error ? error.message : String(error),
1335
+ orderCount: ordersSnapshot.length
1336
+ });
1337
+ }
1338
+ }
1339
+ /**
1340
+ * 单条 upsert 订单到 SQLite;用于 overwriteExistingOrder 等单条覆盖场景。
1341
+ *
1342
+ * @example
1343
+ * await this.updateOrderInSQLite(freshOrder)
1344
+ */
1345
+ async updateOrderInSQLite(order, source) {
1346
+ if (!this.dbManager || !this.getOrderStorageKey(order)) {
1347
+ this.pushOrderFlowLog("updateOrderInSQLite.skip", {
1348
+ source,
1349
+ hasDbManager: !!this.dbManager,
1350
+ orderId: (order == null ? void 0 : order.order_id) ?? null
1351
+ });
769
1352
  return;
1353
+ }
1354
+ const orderSnapshot = (0, import_lodash_es.cloneDeep)(order);
1355
+ try {
1356
+ await this.runInOrderSQLiteSaveQueue(async () => {
1357
+ let writeMethod = "none";
1358
+ this.pushOrderFlowLog("updateOrderInSQLite.start", {
1359
+ source,
1360
+ orderId: orderSnapshot.order_id ?? null,
1361
+ storageKey: this.getOrderStorageKey(orderSnapshot)
1362
+ });
1363
+ this.logInfo("updateOrderInSQLite-开始", {
1364
+ source,
1365
+ orderId: orderSnapshot.order_id ?? null,
1366
+ storageKey: this.getOrderStorageKey(orderSnapshot)
1367
+ });
1368
+ if (typeof this.dbManager.update === "function") {
1369
+ writeMethod = "update";
1370
+ await this.dbManager.update(INDEXDB_STORE_NAME, orderSnapshot);
1371
+ } else if (typeof this.dbManager.bulkUpdate === "function") {
1372
+ writeMethod = "bulkUpdate";
1373
+ await this.dbManager.bulkUpdate(INDEXDB_STORE_NAME, [orderSnapshot]);
1374
+ } else if (typeof this.dbManager.bulkAdd === "function") {
1375
+ writeMethod = "bulkAdd";
1376
+ await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, [orderSnapshot]);
1377
+ }
1378
+ const writeSeq = this.trackOrderWrite(
1379
+ source,
1380
+ writeMethod,
1381
+ [orderSnapshot],
1382
+ {},
1383
+ "singleUpdate"
1384
+ );
1385
+ this.recordRecentSqliteWrite(source, [orderSnapshot]);
1386
+ this.pushOrderFlowLog("updateOrderInSQLite.done", {
1387
+ source,
1388
+ writeSeq,
1389
+ orderId: orderSnapshot.order_id ?? null,
1390
+ storageKey: this.getOrderStorageKey(orderSnapshot),
1391
+ writeMethod
1392
+ });
1393
+ this.logInfo("updateOrderInSQLite-完成", {
1394
+ orderId: orderSnapshot.order_id ?? null
1395
+ });
1396
+ });
1397
+ } catch (error) {
1398
+ this.pushOrderFlowLog("updateOrderInSQLite.error", {
1399
+ source,
1400
+ error: error instanceof Error ? error.message : String(error),
1401
+ orderId: orderSnapshot.order_id ?? null
1402
+ });
1403
+ this.logError("单条保存订单到 SQLite 失败", {
1404
+ error: error instanceof Error ? error.message : String(error),
1405
+ orderId: orderSnapshot.order_id ?? null
1406
+ });
1407
+ }
1408
+ }
1409
+ /**
1410
+ * 全量快照替换 orders 表(clear + bulkAdd),用于 SSE 全量拉取与营业日窗口裁剪。
1411
+ *
1412
+ * @example
1413
+ * await this.replaceOrdersSnapshotInSQLite(orderList)
1414
+ */
1415
+ async replaceOrdersSnapshotInSQLite(orderList, source) {
1416
+ if (!this.dbManager) {
1417
+ this.pushOrderFlowLog("replaceOrdersSnapshotInSQLite.skip", { source, count: orderList.length });
1418
+ return;
1419
+ }
770
1420
  const orderListSnapshot = (0, import_lodash_es.cloneDeep)(orderList);
771
1421
  try {
772
1422
  await this.runInOrderSQLiteSaveQueue(async () => {
773
- this.logInfo("saveOrdersToSQLite-开始", {
1423
+ this.pushOrderFlowLog("replaceOrdersSnapshotInSQLite.start", {
1424
+ source,
1425
+ count: orderListSnapshot.length
1426
+ });
1427
+ this.logInfo("replaceOrdersSnapshotInSQLite-开始", {
1428
+ source,
774
1429
  count: orderListSnapshot.length
775
1430
  });
776
1431
  await this.dbManager.clear(INDEXDB_STORE_NAME);
777
- this.logInfo("saveOrdersToSQLite-clear完成", {
1432
+ this.pushOrderFlowLog("replaceOrdersSnapshotInSQLite.cleared", {
1433
+ source,
778
1434
  count: orderListSnapshot.length
779
1435
  });
780
- if (orderListSnapshot.length === 0)
1436
+ this.logInfo("replaceOrdersSnapshotInSQLite-clear完成", {
1437
+ count: orderListSnapshot.length
1438
+ });
1439
+ if (orderListSnapshot.length === 0) {
1440
+ this.pushOrderFlowLog("replaceOrdersSnapshotInSQLite.doneEmpty", { source });
781
1441
  return;
1442
+ }
782
1443
  await this.dbManager.bulkAdd(INDEXDB_STORE_NAME, orderListSnapshot);
783
- this.logInfo("saveOrdersToSQLite-bulkAdd完成", {
1444
+ const writeSeq = this.trackOrderWrite(
1445
+ source,
1446
+ "clear+bulkAdd",
1447
+ orderListSnapshot,
1448
+ {},
1449
+ "snapshot"
1450
+ );
1451
+ this.recordRecentSqliteWrite(source, orderListSnapshot);
1452
+ this.pushOrderFlowLog("replaceOrdersSnapshotInSQLite.done", {
1453
+ source,
1454
+ writeSeq,
1455
+ count: orderListSnapshot.length,
1456
+ writeMethod: "clear+bulkAdd"
1457
+ });
1458
+ this.logInfo("replaceOrdersSnapshotInSQLite-bulkAdd完成", {
784
1459
  count: orderListSnapshot.length
785
1460
  });
786
1461
  });
787
1462
  } catch (error) {
788
- this.logError("保存订单到 SQLite 失败", {
1463
+ this.pushOrderFlowLog("replaceOrdersSnapshotInSQLite.error", {
1464
+ source,
1465
+ error: error instanceof Error ? error.message : String(error),
1466
+ orderList: orderListSnapshot.length
1467
+ });
1468
+ this.logError("全量保存订单到 SQLite 失败", {
789
1469
  error: error instanceof Error ? error.message : String(error),
790
1470
  orderList: orderListSnapshot.length
791
1471
  });