@pisell/pisellos 2.2.210 → 2.2.211

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 (53) hide show
  1. package/dist/modules/BookingContext/index.d.ts +13 -2
  2. package/dist/modules/BookingContext/index.js +198 -68
  3. package/dist/modules/Order/index.d.ts +1 -0
  4. package/dist/modules/Order/index.js +62 -28
  5. package/dist/modules/Order/types.d.ts +4 -1
  6. package/dist/modules/Order/utils.d.ts +1 -0
  7. package/dist/modules/Order/utils.js +11 -6
  8. package/dist/modules/Quotation/index.js +2 -1
  9. package/dist/modules/SalesSummary/index.d.ts +1 -0
  10. package/dist/modules/SalesSummary/index.js +29 -15
  11. package/dist/modules/SurchargeList/index.d.ts +16 -0
  12. package/dist/modules/SurchargeList/index.js +162 -0
  13. package/dist/modules/SurchargeList/types.d.ts +11 -0
  14. package/dist/modules/SurchargeList/types.js +1 -0
  15. package/dist/modules/index.d.ts +1 -0
  16. package/dist/modules/index.js +1 -0
  17. package/dist/server/index.d.ts +8 -0
  18. package/dist/server/index.js +1075 -915
  19. package/dist/server/modules/order/index.d.ts +9 -0
  20. package/dist/server/modules/order/index.js +557 -411
  21. package/dist/server/modules/order/utils/filterOrders.js +3 -2
  22. package/dist/server/test.json +713 -0
  23. package/dist/server/utils/small-ticket.d.ts +1 -1
  24. package/dist/server/utils/small-ticket.js +1 -1
  25. package/dist/solution/BookingByStep/index.d.ts +2 -2
  26. package/dist/solution/BookingTicket/index.js +22 -20
  27. package/lib/modules/BookingContext/index.d.ts +13 -2
  28. package/lib/modules/BookingContext/index.js +99 -28
  29. package/lib/modules/Order/index.d.ts +1 -0
  30. package/lib/modules/Order/index.js +12 -1
  31. package/lib/modules/Order/types.d.ts +4 -1
  32. package/lib/modules/Order/utils.d.ts +1 -0
  33. package/lib/modules/Order/utils.js +10 -3
  34. package/lib/modules/Quotation/index.js +1 -1
  35. package/lib/modules/SalesSummary/index.d.ts +1 -0
  36. package/lib/modules/SalesSummary/index.js +11 -1
  37. package/lib/modules/SurchargeList/index.d.ts +16 -0
  38. package/lib/modules/SurchargeList/index.js +89 -0
  39. package/lib/modules/SurchargeList/types.d.ts +11 -0
  40. package/lib/modules/SurchargeList/types.js +17 -0
  41. package/lib/modules/index.d.ts +1 -0
  42. package/lib/modules/index.js +2 -0
  43. package/lib/server/index.d.ts +8 -0
  44. package/lib/server/index.js +134 -19
  45. package/lib/server/modules/order/index.d.ts +9 -0
  46. package/lib/server/modules/order/index.js +107 -19
  47. package/lib/server/modules/order/utils/filterOrders.js +3 -2
  48. package/lib/server/test.json +713 -0
  49. package/lib/server/utils/small-ticket.d.ts +1 -1
  50. package/lib/server/utils/small-ticket.js +1 -35
  51. package/lib/solution/BookingByStep/index.d.ts +2 -2
  52. package/lib/solution/BookingTicket/index.js +12 -7
  53. package/package.json +1 -1
@@ -0,0 +1,17 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __copyProps = (to, from, except, desc) => {
6
+ if (from && typeof from === "object" || typeof from === "function") {
7
+ for (let key of __getOwnPropNames(from))
8
+ if (!__hasOwnProp.call(to, key) && key !== except)
9
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
10
+ }
11
+ return to;
12
+ };
13
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
14
+
15
+ // src/modules/SurchargeList/types.ts
16
+ var types_exports = {};
17
+ module.exports = __toCommonJS(types_exports);
@@ -12,6 +12,7 @@ export * from './Resource';
12
12
  export * from './Step';
13
13
  export * from './Summary';
14
14
  export * from './SalesSummary';
15
+ export * from './SurchargeList';
15
16
  export * from './Schedule';
16
17
  export * from './Quotation';
17
18
  export * from './ScanOrderLogger';
@@ -30,6 +30,7 @@ __reExport(modules_exports, require("./Resource"), module.exports);
30
30
  __reExport(modules_exports, require("./Step"), module.exports);
31
31
  __reExport(modules_exports, require("./Summary"), module.exports);
32
32
  __reExport(modules_exports, require("./SalesSummary"), module.exports);
33
+ __reExport(modules_exports, require("./SurchargeList"), module.exports);
33
34
  __reExport(modules_exports, require("./Schedule"), module.exports);
34
35
  __reExport(modules_exports, require("./Quotation"), module.exports);
35
36
  __reExport(modules_exports, require("./ScanOrderLogger"), module.exports);
@@ -51,6 +52,7 @@ __reExport(modules_exports, require("./BookingContext"), module.exports);
51
52
  ...require("./Step"),
52
53
  ...require("./Summary"),
53
54
  ...require("./SalesSummary"),
55
+ ...require("./SurchargeList"),
54
56
  ...require("./Schedule"),
55
57
  ...require("./Quotation"),
56
58
  ...require("./ScanOrderLogger"),
@@ -27,6 +27,8 @@ declare class Server {
27
27
  payment?: PaymentServerModule;
28
28
  private paymentRouteModule?;
29
29
  private paymentRouteModuleInFlight?;
30
+ private quotationAvailableCache;
31
+ private quotationAvailableInFlight;
30
32
  /** GET 前缀路由(最长前缀优先匹配) */
31
33
  private prefixRouterGet;
32
34
  router: Router;
@@ -177,6 +179,9 @@ declare class Server {
177
179
  private registerServerRoutes;
178
180
  private getPaymentRouteModule;
179
181
  private handlePaymentMethods;
182
+ private handleQuotationAvailable;
183
+ private fetchQuotationAvailableFromAPI;
184
+ private isSuccessfulRemoteResponse;
180
185
  /**
181
186
  * 根据 subscriberId 移除商品查询订阅者
182
187
  */
@@ -432,6 +437,9 @@ declare class Server {
432
437
  private shouldForceRemoteSalesDetail;
433
438
  private buildOrderSalesDetailBackendPath;
434
439
  private extractOrderDataFromCheckoutResponse;
440
+ private getCheckoutExternalSaleNumber;
441
+ private buildCheckoutSyncSuccessPatch;
442
+ private isMergeableCheckoutOrder;
435
443
  private normalizeCheckoutResponse;
436
444
  private isCheckoutResponseRejected;
437
445
  private extractBackendErrorResponse;
@@ -53,6 +53,8 @@ var import_small_ticket = require("./utils/small-ticket");
53
53
  __reExport(server_exports, require("./modules"), module.exports);
54
54
  var Server = class {
55
55
  constructor(core) {
56
+ this.quotationAvailableCache = /* @__PURE__ */ new Map();
57
+ this.quotationAvailableInFlight = /* @__PURE__ */ new Map();
56
58
  /** GET 前缀路由(最长前缀优先匹配) */
57
59
  this.prefixRouterGet = [];
58
60
  // 路由注册表
@@ -167,6 +169,29 @@ var Server = class {
167
169
  data: payMethods
168
170
  };
169
171
  };
172
+ this.handleQuotationAvailable = async ({ data }) => {
173
+ const queryPayload = data && typeof data === "object" ? { ...data } : {};
174
+ const cacheKey = this.stableSerialize(queryPayload);
175
+ if (this.quotationAvailableCache.has(cacheKey)) {
176
+ this.logInfo("handleQuotationAvailable: 命中运行时缓存", { cacheKey });
177
+ return this.quotationAvailableCache.get(cacheKey);
178
+ }
179
+ const inFlight = this.quotationAvailableInFlight.get(cacheKey);
180
+ if (inFlight) {
181
+ this.logInfo("handleQuotationAvailable: 复用进行中的请求", { cacheKey });
182
+ return inFlight;
183
+ }
184
+ const requestPromise = this.fetchQuotationAvailableFromAPI(queryPayload).then((response) => {
185
+ if (this.isSuccessfulRemoteResponse(response)) {
186
+ this.quotationAvailableCache.set(cacheKey, response);
187
+ }
188
+ return response;
189
+ }).finally(() => {
190
+ this.quotationAvailableInFlight.delete(cacheKey);
191
+ });
192
+ this.quotationAvailableInFlight.set(cacheKey, requestPromise);
193
+ return requestPromise;
194
+ };
170
195
  /**
171
196
  * 处理商品查询请求
172
197
  * 存储订阅者信息,便于数据变更时推送最新结果
@@ -1091,7 +1116,7 @@ var Server = class {
1091
1116
  return this.taskTimeout("app.request 不可用");
1092
1117
  }
1093
1118
  try {
1094
- const response = await this.app.request.post("/shop/order/sales/checkout", data, {
1119
+ const response = await this.app.request.post(backendPath, data, {
1095
1120
  isShopApi: true,
1096
1121
  customToast: () => {
1097
1122
  }
@@ -1105,28 +1130,47 @@ var Server = class {
1105
1130
  return this.taskFail("BACKEND_REJECTED", message, response);
1106
1131
  }
1107
1132
  const fresh = this.extractOrderDataFromCheckoutResponse(response);
1108
- if (!fresh) {
1109
- this.logWarning(`${title}: sync_sales 返回未包含可同步订单`, {
1110
- backendPath,
1111
- response
1112
- });
1113
- return this.taskTimeout("checkout 返回未包含可同步订单");
1114
- }
1115
- const syncedOrder = { ...fresh, need_sync: 0 };
1116
- if (this.order) {
1133
+ const externalSaleNumber = this.getCheckoutExternalSaleNumber(data, payload);
1134
+ const shouldMergeRemoteOrder = fresh ? this.isMergeableCheckoutOrder(fresh, externalSaleNumber) : false;
1135
+ let syncedOrder;
1136
+ if (this.order && fresh && shouldMergeRemoteOrder) {
1137
+ syncedOrder = {
1138
+ ...fresh,
1139
+ external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
1140
+ need_sync: 0
1141
+ };
1117
1142
  await this.order.upsertOrdersFromRemote([syncedOrder]);
1118
- this.logInfo(`${title}: sync_sales 订单已同步到本地`, {
1143
+ this.logInfo(`${title}: sync_sales 完整订单已同步到本地`, {
1119
1144
  order_id: fresh.order_id,
1120
- external_sale_number: fresh.external_sale_number,
1145
+ external_sale_number: syncedOrder.external_sale_number,
1121
1146
  order_number: fresh.order_number
1122
1147
  });
1148
+ } else if (this.order && externalSaleNumber && typeof this.order.markOrderSyncedByExternalSaleNumber === "function") {
1149
+ const patch = this.buildCheckoutSyncSuccessPatch(fresh);
1150
+ const result = await this.order.markOrderSyncedByExternalSaleNumber({
1151
+ externalSaleNumber,
1152
+ patch
1153
+ });
1154
+ syncedOrder = (result == null ? void 0 : result.order) || {
1155
+ ...data,
1156
+ ...patch,
1157
+ external_sale_number: externalSaleNumber,
1158
+ need_sync: 0
1159
+ };
1160
+ this.logInfo(`${title}: sync_sales 已按 external_sale_number 标记本地订单`, {
1161
+ order_id: (syncedOrder == null ? void 0 : syncedOrder.order_id) ?? null,
1162
+ external_sale_number: externalSaleNumber,
1163
+ hasRemoteOrder: !!fresh,
1164
+ mergedRemoteOrder: false
1165
+ });
1123
1166
  } else {
1124
1167
  this.logWarning(`${title}: sync_sales Order 模块未注册`, {
1125
1168
  backendPath,
1126
- order_id: fresh.order_id
1169
+ external_sale_number: externalSaleNumber,
1170
+ order_id: fresh == null ? void 0 : fresh.order_id
1127
1171
  });
1128
1172
  }
1129
- if (this.shouldPrintSyncedOrder({ checkoutData: data, syncedOrder })) {
1173
+ if (syncedOrder && this.shouldPrintSyncedOrder({ checkoutData: data, syncedOrder })) {
1130
1174
  await this.dispatchPrintOtherReceiptTask({
1131
1175
  checkoutData: data,
1132
1176
  syncedOrder,
@@ -1135,7 +1179,7 @@ var Server = class {
1135
1179
  });
1136
1180
  }
1137
1181
  return this.taskOk({
1138
- order: syncedOrder,
1182
+ order: syncedOrder ?? null,
1139
1183
  response: this.normalizeCheckoutResponse(response)
1140
1184
  });
1141
1185
  } catch (error) {
@@ -1504,6 +1548,16 @@ var Server = class {
1504
1548
  path: "/shop/pay/custom-payment/all",
1505
1549
  handler: this.handlePaymentMethods.bind(this)
1506
1550
  },
1551
+ {
1552
+ method: "get",
1553
+ path: "/shop/quotation/available",
1554
+ handler: this.handleQuotationAvailable.bind(this)
1555
+ },
1556
+ {
1557
+ method: "get",
1558
+ path: "/quotation/available",
1559
+ handler: this.handleQuotationAvailable.bind(this)
1560
+ },
1507
1561
  {
1508
1562
  method: "post",
1509
1563
  path: "/shop/order/sales/checkout",
@@ -1552,6 +1606,31 @@ var Server = class {
1552
1606
  });
1553
1607
  return this.paymentRouteModuleInFlight;
1554
1608
  }
1609
+ async fetchQuotationAvailableFromAPI(data) {
1610
+ var _a;
1611
+ const requester = ((_a = this.app) == null ? void 0 : _a.request) || this.core.getPlugin("request");
1612
+ if (!(requester == null ? void 0 : requester.get)) {
1613
+ this.logError("fetchQuotationAvailableFromAPI: request 不可用");
1614
+ return {
1615
+ code: 500,
1616
+ message: "request 不可用",
1617
+ data: { list: [] },
1618
+ status: false
1619
+ };
1620
+ }
1621
+ return requester.get("/shop/quotation/available", data);
1622
+ }
1623
+ isSuccessfulRemoteResponse(response) {
1624
+ if (!response)
1625
+ return false;
1626
+ if (response.status === false)
1627
+ return false;
1628
+ if (typeof response.status === "number" && response.status >= 400)
1629
+ return false;
1630
+ if (response.code !== void 0 && response.code !== 200 && response.code !== "200")
1631
+ return false;
1632
+ return true;
1633
+ }
1555
1634
  /**
1556
1635
  * 根据 subscriberId 移除商品查询订阅者
1557
1636
  */
@@ -2214,7 +2293,7 @@ var Server = class {
2214
2293
  return res == null ? void 0 : res.short_number;
2215
2294
  }
2216
2295
  }
2217
- return this.getAppData("device_id") || 0;
2296
+ return String(this.getAppData("device_id") || 0).slice(-2);
2218
2297
  }
2219
2298
  buildCheckoutTaskIdempotencyKey(data) {
2220
2299
  const identity = (data == null ? void 0 : data.request_unique_idempotency_token) || (data == null ? void 0 : data.external_sale_number) || (data == null ? void 0 : data.order_id) || (data == null ? void 0 : data.shop_order_number) || (data == null ? void 0 : data.shop_full_order_number);
@@ -2261,7 +2340,7 @@ var Server = class {
2261
2340
  return next;
2262
2341
  }
2263
2342
  async dispatchCheckoutSyncTask(params) {
2264
- var _a, _b, _c;
2343
+ var _a, _b, _c, _d;
2265
2344
  this.registerDeviceTaskActions();
2266
2345
  const deviceTask = this.getDeviceTaskPlugin();
2267
2346
  const debugDeviceId = await this.getShortNumberOrDeviceId();
@@ -2277,6 +2356,7 @@ var Server = class {
2277
2356
  payload: {
2278
2357
  backendPath: params.backendPath,
2279
2358
  data: params.data,
2359
+ external_sale_number: (_a = params.data) == null ? void 0 : _a.external_sale_number,
2280
2360
  title: params.title
2281
2361
  },
2282
2362
  retry_limit: 5,
@@ -2284,7 +2364,7 @@ var Server = class {
2284
2364
  name: "同步订单",
2285
2365
  source: "server",
2286
2366
  source_type: "order",
2287
- source_id: ((_a = params.data) == null ? void 0 : _a.order_id) || ((_b = params.data) == null ? void 0 : _b.external_sale_number) || ((_c = params.data) == null ? void 0 : _c.shop_order_number)
2367
+ source_id: ((_b = params.data) == null ? void 0 : _b.order_id) || ((_c = params.data) == null ? void 0 : _c.external_sale_number) || ((_d = params.data) == null ? void 0 : _d.shop_order_number)
2288
2368
  });
2289
2369
  this.logInfo(`${params.title}: sync_sales 任务已派发`, {
2290
2370
  uuid: result == null ? void 0 : result.uuid,
@@ -2381,7 +2461,9 @@ var Server = class {
2381
2461
  });
2382
2462
  if ((pendingResult == null ? void 0 : pendingResult.status) === true) {
2383
2463
  const pendingOrder = pendingResult.data;
2384
- if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData) && this.isSalesOrderFullyPaid(pendingOrder)) {
2464
+ if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData) && this.isSalesOrderFullyPaid(pendingOrder) && // TODO 这里先加个兼容,只有 type 为 virtual 才走打印
2465
+ // 后期需要迁移到 picoding ,根据工作流配置
2466
+ checkoutData.type === "virtual") {
2385
2467
  await this.dispatchLocalReceiptPrint({
2386
2468
  checkoutData,
2387
2469
  order: pendingOrder,
@@ -2771,6 +2853,39 @@ var Server = class {
2771
2853
  }
2772
2854
  return null;
2773
2855
  }
2856
+ getCheckoutExternalSaleNumber(data, payload) {
2857
+ var _a;
2858
+ const candidates = [
2859
+ payload == null ? void 0 : payload.external_sale_number,
2860
+ data == null ? void 0 : data.external_sale_number,
2861
+ (_a = payload == null ? void 0 : payload.data) == null ? void 0 : _a.external_sale_number
2862
+ ];
2863
+ const value = candidates.find((candidate) => candidate !== void 0 && candidate !== null && candidate !== "");
2864
+ return value === void 0 ? void 0 : String(value);
2865
+ }
2866
+ buildCheckoutSyncSuccessPatch(fresh) {
2867
+ if (!fresh)
2868
+ return {};
2869
+ const patch = {};
2870
+ if (fresh.order_id !== void 0 && fresh.order_id !== null)
2871
+ patch.order_id = fresh.order_id;
2872
+ if (fresh.order_number !== void 0 && fresh.order_number !== null) {
2873
+ patch.order_number = fresh.order_number;
2874
+ }
2875
+ return patch;
2876
+ }
2877
+ isMergeableCheckoutOrder(order, externalSaleNumber) {
2878
+ if (!order || typeof order !== "object")
2879
+ return false;
2880
+ const orderExternalSaleNumber = order.external_sale_number;
2881
+ if (externalSaleNumber && orderExternalSaleNumber !== void 0 && orderExternalSaleNumber !== null && String(orderExternalSaleNumber) !== externalSaleNumber) {
2882
+ return false;
2883
+ }
2884
+ if (externalSaleNumber && (orderExternalSaleNumber === void 0 || orderExternalSaleNumber === null || orderExternalSaleNumber === "")) {
2885
+ return false;
2886
+ }
2887
+ return Array.isArray(order.products) || Array.isArray(order.bookings) || Array.isArray(order.payments) || !!order.summary || order.order_number !== void 0 || order.payment_status !== void 0 || order.status !== void 0;
2888
+ }
2774
2889
  normalizeCheckoutResponse(response) {
2775
2890
  if (response && typeof response === "object" && (response.code !== void 0 || response.status !== void 0)) {
2776
2891
  return response;
@@ -87,6 +87,7 @@ export declare class OrderModule extends BaseModule implements Module {
87
87
  */
88
88
  silentRefresh(): Promise<OrderData[]>;
89
89
  getOrdersByResourceId(resourceId: string | number): OrderData[];
90
+ private normalizeOrderForMemoryList;
90
91
  /**
91
92
  * 仅覆盖本地已存在的订单;不存在则直接跳过,不落库、不 emit。
92
93
  * 适用于"按 order_id 主动刷新本地订单详情"的代理场景。
@@ -99,6 +100,13 @@ export declare class OrderModule extends BaseModule implements Module {
99
100
  * 供 /update/localOrder 等在「本地尚无该单」时写入新建单。
100
101
  */
101
102
  upsertOrdersFromRemote(freshOrders: OrderData[]): Promise<void>;
103
+ markOrderSyncedByExternalSaleNumber(params: {
104
+ externalSaleNumber: OrderId;
105
+ patch?: Partial<OrderData>;
106
+ }): Promise<{
107
+ updated: boolean;
108
+ order?: OrderData;
109
+ }>;
102
110
  /**
103
111
  * 将本地待同步订单按 SQLite storage key 合并进 store 并落库。
104
112
  * checkout 离线兜底可能没有 order_id,但通常会有 external_sale_number。
@@ -111,6 +119,7 @@ export declare class OrderModule extends BaseModule implements Module {
111
119
  getRoutes(): RouteDefinition[];
112
120
  destroy(): void;
113
121
  private syncOrdersMap;
122
+ private getOrderIdentityKeys;
114
123
  private extractResourceIds;
115
124
  private getOrderDateKey;
116
125
  /**
@@ -45,7 +45,8 @@ var ORDER_SILENT_REFRESH_MIN_INTERVAL_MS = 3e4;
45
45
  var ORDER_BUSINESS_WRITE_SOURCES = /* @__PURE__ */ new Set([
46
46
  "upsertOrdersFromRemote",
47
47
  "upsertPendingSyncOrders",
48
- "overwriteExistingOrder"
48
+ "overwriteExistingOrder",
49
+ "markOrderSyncedByExternalSaleNumber"
49
50
  ]);
50
51
  var OrderModule = class extends import_BaseModule.BaseModule {
51
52
  constructor(name, version) {
@@ -72,7 +73,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
72
73
  async emitOrdersChanged(changedOrders = [], source) {
73
74
  const payload = {
74
75
  list: this.store.list,
75
- changedOrders,
76
+ changedOrders: changedOrders.map((order) => this.normalizeOrderForMemoryList(order)),
76
77
  source
77
78
  };
78
79
  await this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, payload);
@@ -131,7 +132,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
131
132
  }
132
133
  }
133
134
  if (Array.isArray((_b = options == null ? void 0 : options.initialState) == null ? void 0 : _b.list)) {
134
- this.store.list = options.initialState.list;
135
+ this.store.list = options.initialState.list.map((order) => this.normalizeOrderForMemoryList(order));
135
136
  this.syncOrdersMap();
136
137
  this.emitOrdersChanged([], "initialState");
137
138
  } else {
@@ -377,9 +378,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
377
378
  const localOrder = orders.find((order) => this.isOrderLookupMatch(order, key));
378
379
  if (!localOrder)
379
380
  return null;
380
- this.store.list = orders;
381
+ this.store.list = orders.map((order) => this.normalizeOrderForMemoryList(order));
381
382
  this.syncOrdersMap();
382
- return localOrder;
383
+ return this.normalizeOrderForMemoryList(localOrder);
383
384
  }
384
385
  async loadOrdersByServer() {
385
386
  var _a;
@@ -402,16 +403,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
402
403
  this.markOrderPulledAtNow();
403
404
  this.lastServerFullFetchAtMs = Date.now();
404
405
  } catch {
405
- orderList = [];
406
- this.logInfo("loadOrdersByServer-SSE拉取失败,回退为空数组");
406
+ this.logInfo("loadOrdersByServer-SSE拉取失败,保持当前内存订单");
407
+ return this.store.list;
407
408
  }
408
409
  }
409
- await this.replaceOrdersSnapshotInSQLite(orderList, "loadOrdersByServer");
410
+ const mergedOrders = await this.replaceOrdersSnapshotInSQLite(orderList, "loadOrdersByServer");
411
+ const memoryOrders = mergedOrders.map((order) => this.normalizeOrderForMemoryList(order));
410
412
  this.logInfo("loadOrdersByServer-结束", {
411
- count: orderList.length
413
+ count: memoryOrders.length
412
414
  });
413
- await this.core.effects.emit(import_types.OrderHooks.onOrdersLoaded, orderList);
414
- return orderList;
415
+ await this.core.effects.emit(import_types.OrderHooks.onOrdersLoaded, memoryOrders);
416
+ return memoryOrders;
415
417
  }
416
418
  /**
417
419
  * 静默全量刷新:后台重新拉取全量 SSE 订单数据并更新本地
@@ -453,6 +455,19 @@ var OrderModule = class extends import_BaseModule.BaseModule {
453
455
  const ids = this.resourceIdIndex.get(String(resourceId)) || [];
454
456
  return ids.map((id) => this.store.map.get(id)).filter((order) => !!order);
455
457
  }
458
+ normalizeOrderForMemoryList(order) {
459
+ const externalSaleNumber = order == null ? void 0 : order.external_sale_number;
460
+ if ((order == null ? void 0 : order.order_id) !== void 0 && (order == null ? void 0 : order.order_id) !== null && (order == null ? void 0 : order.order_id) !== "") {
461
+ return order;
462
+ }
463
+ if (externalSaleNumber === void 0 || externalSaleNumber === null || externalSaleNumber === "") {
464
+ return order;
465
+ }
466
+ return {
467
+ ...order,
468
+ order_id: externalSaleNumber
469
+ };
470
+ }
456
471
  /**
457
472
  * 仅覆盖本地已存在的订单;不存在则直接跳过,不落库、不 emit。
458
473
  * 适用于"按 order_id 主动刷新本地订单详情"的代理场景。
@@ -499,6 +514,51 @@ var OrderModule = class extends import_BaseModule.BaseModule {
499
514
  this.logInfo("upsertOrdersFromRemote-开始", { count: freshOrders.length });
500
515
  await this.mergeOrdersToStore(freshOrders, "upsertOrdersFromRemote");
501
516
  }
517
+ async markOrderSyncedByExternalSaleNumber(params) {
518
+ const externalSaleNumber = params.externalSaleNumber;
519
+ if (externalSaleNumber === void 0 || externalSaleNumber === null || externalSaleNumber === "") {
520
+ this.logError("markOrderSyncedByExternalSaleNumber-缺少 external_sale_number");
521
+ return { updated: false };
522
+ }
523
+ const key = this.getIdKey(externalSaleNumber);
524
+ const targetIndex = this.store.list.findIndex((order) => {
525
+ const value = order == null ? void 0 : order.external_sale_number;
526
+ if (value === void 0 || value === null || value === "")
527
+ return false;
528
+ return this.getIdKey(value) === key;
529
+ });
530
+ if (targetIndex < 0) {
531
+ this.logInfo("markOrderSyncedByExternalSaleNumber-本地订单不存在,跳过", {
532
+ external_sale_number: externalSaleNumber
533
+ });
534
+ return { updated: false };
535
+ }
536
+ const existing = this.store.list[targetIndex];
537
+ const nextOrder = this.normalizeRemoteSyncedOrder({
538
+ ...existing,
539
+ ...params.patch || {},
540
+ external_sale_number: existing.external_sale_number ?? externalSaleNumber,
541
+ need_sync: 0
542
+ });
543
+ const storageKey = this.getOrderStorageKey(nextOrder) || key;
544
+ this.store.list = this.store.list.map((order, index) => {
545
+ if (index !== targetIndex)
546
+ return order;
547
+ return nextOrder;
548
+ });
549
+ this.syncOrdersMap();
550
+ await this.patchOrdersInSQLite(
551
+ [nextOrder],
552
+ "markOrderSyncedByExternalSaleNumber",
553
+ { [storageKey]: "update" }
554
+ );
555
+ this.logInfo("markOrderSyncedByExternalSaleNumber-完成", {
556
+ external_sale_number: externalSaleNumber,
557
+ order_id: nextOrder.order_id ?? null
558
+ });
559
+ await this.emitOrdersChanged([nextOrder], "markOrderSyncedByExternalSaleNumber");
560
+ return { updated: true, order: nextOrder };
561
+ }
502
562
  /**
503
563
  * 将本地待同步订单按 SQLite storage key 合并进 store 并落库。
504
564
  * checkout 离线兜底可能没有 order_id,但通常会有 external_sale_number。
@@ -509,11 +569,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
509
569
  return;
510
570
  }
511
571
  const pendingMap = /* @__PURE__ */ new Map();
572
+ const memoryPendingMap = /* @__PURE__ */ new Map();
512
573
  for (const order of pendingOrders) {
513
574
  const storageKey = this.getOrderStorageKey(order);
514
575
  if (!storageKey)
515
576
  continue;
516
577
  pendingMap.set(storageKey, order);
578
+ memoryPendingMap.set(storageKey, this.normalizeOrderForMemoryList(order));
517
579
  }
518
580
  if (pendingMap.size === 0) {
519
581
  this.logError("upsertPendingSyncOrders-订单缺少可落库标识", {
@@ -528,12 +590,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
528
590
  const storageKey = this.getOrderStorageKey(order);
529
591
  if (!storageKey || !pendingMap.has(storageKey))
530
592
  return order;
531
- const pendingOrder = pendingMap.get(storageKey);
593
+ const pendingOrder = memoryPendingMap.get(storageKey);
532
594
  pendingMap.delete(storageKey);
595
+ memoryPendingMap.delete(storageKey);
533
596
  mergeActions[storageKey] = "update";
534
597
  return pendingOrder;
535
598
  });
536
- for (const [storageKey, order] of pendingMap.entries()) {
599
+ for (const [storageKey, order] of memoryPendingMap.entries()) {
537
600
  mergeActions[storageKey] = "insert";
538
601
  updatedList.push(order);
539
602
  }
@@ -545,6 +608,11 @@ var OrderModule = class extends import_BaseModule.BaseModule {
545
608
  storeOrderCountAfter: this.store.list.length
546
609
  });
547
610
  this.emitOrdersChanged(patchedOrders, "upsertPendingSyncOrders");
611
+ await this.core.effects.emit(import_types.OrderHooks.onOrdersChanged, {
612
+ list: this.store.list,
613
+ changedOrders: patchedOrders.map((order) => this.normalizeOrderForMemoryList(order)),
614
+ source: "upsertPendingSyncOrders"
615
+ });
548
616
  }
549
617
  /**
550
618
  * 通过 SSE 按自定义 query 拉取订单(支持 select/with 精简字段)
@@ -581,21 +649,38 @@ var OrderModule = class extends import_BaseModule.BaseModule {
581
649
  this.store.map.clear();
582
650
  this.resourceIdIndex.clear();
583
651
  for (const order of this.store.list) {
584
- const id = order.order_id;
585
- if (id === void 0 || id === null)
652
+ const identityKeys = this.getOrderIdentityKeys(order);
653
+ if (identityKeys.length === 0)
586
654
  continue;
587
- this.store.map.set(this.getIdKey(id), order);
655
+ for (const identityKey of identityKeys) {
656
+ this.store.map.set(identityKey, order);
657
+ }
588
658
  const resourceIds = this.extractResourceIds(order);
659
+ const primaryIdentity = identityKeys[0];
589
660
  for (const resourceId of resourceIds) {
590
661
  const key = String(resourceId);
591
662
  const existing = this.resourceIdIndex.get(key) || [];
592
- if (existing.some((eid) => this.getIdKey(eid) === this.getIdKey(id)))
663
+ if (existing.some((eid) => this.getIdKey(eid) === primaryIdentity))
593
664
  continue;
594
- existing.push(id);
665
+ existing.push(primaryIdentity);
595
666
  this.resourceIdIndex.set(key, existing);
596
667
  }
597
668
  }
598
669
  }
670
+ getOrderIdentityKeys(order) {
671
+ const keys = [];
672
+ const id = order.order_id;
673
+ if (id !== void 0 && id !== null && id !== "") {
674
+ keys.push(this.getIdKey(id));
675
+ }
676
+ const externalSaleNumber = order == null ? void 0 : order.external_sale_number;
677
+ if (externalSaleNumber !== void 0 && externalSaleNumber !== null && externalSaleNumber !== "") {
678
+ const externalKey = this.getIdKey(externalSaleNumber);
679
+ if (!keys.includes(externalKey))
680
+ keys.push(externalKey);
681
+ }
682
+ return keys;
683
+ }
599
684
  extractResourceIds(order) {
600
685
  const ids = /* @__PURE__ */ new Set();
601
686
  const visitResources = (resources) => {
@@ -1190,9 +1275,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1190
1275
  */
1191
1276
  async replaceOrdersSnapshotInSQLite(orderList, source) {
1192
1277
  if (!this.dbManager) {
1193
- return;
1278
+ return orderList.map((order) => this.normalizeRemoteSyncedOrder(order));
1194
1279
  }
1195
1280
  const remoteSnapshot = (0, import_lodash_es.cloneDeep)(orderList);
1281
+ let mergedSnapshot = remoteSnapshot.map((order) => this.normalizeRemoteSyncedOrder(order));
1196
1282
  try {
1197
1283
  await this.runInOrderSQLiteSaveQueue(async () => {
1198
1284
  const existingOrders = typeof this.dbManager.getAll === "function" ? await this.dbManager.getAll(INDEXDB_STORE_NAME) : [];
@@ -1200,6 +1286,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1200
1286
  remoteSnapshot,
1201
1287
  existingOrders || []
1202
1288
  );
1289
+ mergedSnapshot = orderListSnapshot;
1203
1290
  this.logInfo("replaceOrdersSnapshotInSQLite-开始", {
1204
1291
  source,
1205
1292
  count: orderListSnapshot.length,
@@ -1226,6 +1313,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1226
1313
  orderList: remoteSnapshot.length
1227
1314
  });
1228
1315
  }
1316
+ return mergedSnapshot;
1229
1317
  }
1230
1318
  /**
1231
1319
  * 清空订单模块的内存数据和本地 SQLite 订单表。
@@ -335,8 +335,9 @@ function filterOrders(orders, filters) {
335
335
  }
336
336
  }
337
337
  if (safeFilters.start_time || safeFilters.end_time) {
338
+ const isCreatedIsUndefined = order.created_at === void 0;
338
339
  const orderTime = order.created_at ? typeof order.created_at === "number" ? order.created_at : (0, import_dayjs.default)(String(order.created_at)).valueOf() : 0;
339
- if (safeFilters.start_time) {
340
+ if (safeFilters.start_time && !isCreatedIsUndefined) {
340
341
  const startTs = (0, import_dayjs.default)(safeFilters.start_time).startOf("day").valueOf();
341
342
  if (orderTime < startTs) {
342
343
  rejected.push({
@@ -351,7 +352,7 @@ function filterOrders(orders, filters) {
351
352
  return false;
352
353
  }
353
354
  }
354
- if (safeFilters.end_time) {
355
+ if (safeFilters.end_time && !isCreatedIsUndefined) {
355
356
  const endTs = (0, import_dayjs.default)(safeFilters.end_time).endOf("day").valueOf();
356
357
  if (orderTime > endTs) {
357
358
  rejected.push({