@pisell/pisellos 2.2.205 → 2.2.206

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 (42) hide show
  1. package/dist/modules/OpenData/index.d.ts +1 -0
  2. package/dist/modules/OpenData/index.js +21 -16
  3. package/dist/modules/Order/index.d.ts +9 -0
  4. package/dist/modules/Order/index.js +230 -145
  5. package/dist/modules/Order/types.d.ts +10 -0
  6. package/dist/modules/Order/utils.js +7 -5
  7. package/dist/server/index.d.ts +136 -0
  8. package/dist/server/index.js +2054 -781
  9. package/dist/server/modules/order/index.d.ts +7 -0
  10. package/dist/server/modules/order/index.js +375 -337
  11. package/dist/server/modules/order/types.d.ts +15 -0
  12. package/dist/server/modules/order/types.js +8 -0
  13. package/dist/server/utils/small-ticket.d.ts +69 -0
  14. package/dist/server/utils/small-ticket.js +528 -0
  15. package/dist/solution/BaseSales/index.d.ts +4 -2
  16. package/dist/solution/BaseSales/index.js +248 -188
  17. package/dist/solution/BookingByStep/index.d.ts +1 -1
  18. package/dist/solution/BookingTicket/index.d.ts +8 -1
  19. package/dist/solution/BookingTicket/index.js +443 -263
  20. package/dist/solution/BookingTicket/types.d.ts +2 -1
  21. package/dist/solution/BookingTicket/types.js +3 -1
  22. package/lib/modules/OpenData/index.d.ts +1 -0
  23. package/lib/modules/OpenData/index.js +6 -4
  24. package/lib/modules/Order/index.d.ts +9 -0
  25. package/lib/modules/Order/index.js +59 -3
  26. package/lib/modules/Order/types.d.ts +10 -0
  27. package/lib/modules/Order/utils.js +4 -3
  28. package/lib/server/index.d.ts +136 -0
  29. package/lib/server/index.js +822 -50
  30. package/lib/server/modules/order/index.d.ts +7 -0
  31. package/lib/server/modules/order/index.js +21 -7
  32. package/lib/server/modules/order/types.d.ts +15 -0
  33. package/lib/server/utils/small-ticket.d.ts +69 -0
  34. package/lib/server/utils/small-ticket.js +555 -0
  35. package/lib/solution/BaseSales/index.d.ts +4 -2
  36. package/lib/solution/BaseSales/index.js +47 -1
  37. package/lib/solution/BookingByStep/index.d.ts +1 -1
  38. package/lib/solution/BookingTicket/index.d.ts +8 -1
  39. package/lib/solution/BookingTicket/index.js +108 -1
  40. package/lib/solution/BookingTicket/types.d.ts +2 -1
  41. package/lib/solution/BookingTicket/types.js +5 -0
  42. package/package.json +1 -1
@@ -49,6 +49,7 @@ var import_order = require("./modules/order");
49
49
  var import_types3 = require("./modules/order/types");
50
50
  var import_filterOrders = require("./modules/order/utils/filterOrders");
51
51
  var import_filterBookings = require("./modules/order/utils/filterBookings");
52
+ var import_small_ticket = require("./utils/small-ticket");
52
53
  __reExport(server_exports, require("./modules"), module.exports);
53
54
  var Server = class {
54
55
  constructor(core) {
@@ -70,6 +71,8 @@ var Server = class {
70
71
  this.bookingRemoteCache = /* @__PURE__ */ new Map();
71
72
  this.BOOKING_REMOTE_CACHE_TTL_MS = 5 * 60 * 1e3;
72
73
  this.BOOKING_REMOTE_CACHE_MAX_ENTRIES = 80;
74
+ this.salesSearchSubscribers = /* @__PURE__ */ new Map();
75
+ this.deviceTaskActionsRegistered = false;
73
76
  this.floorPlanQuerySubscribers = /* @__PURE__ */ new Map();
74
77
  // 模块注册表 - 定义所有可用的模块配置
75
78
  this.moduleRegistry = {
@@ -154,7 +157,6 @@ var Server = class {
154
157
  }
155
158
  };
156
159
  this.handlePaymentMethods = async ({ data, config }) => {
157
- debugger;
158
160
  const payment = await this.getPaymentRouteModule();
159
161
  const payMethods = await payment.getPayMethodListAsync({
160
162
  shouldFilter: (data == null ? void 0 : data.filterPaymentMethods) === true || (config == null ? void 0 : config.filterPaymentMethods) === true
@@ -292,6 +294,41 @@ var Server = class {
292
294
  }
293
295
  return { code: 200, message: "ok", status: true };
294
296
  };
297
+ /**
298
+ * 处理 sales 单模块搜索:请求透传后端,仅在 OS 层维护已返回订单号集合。
299
+ *
300
+ * @example
301
+ * await this.handleSalesSearchModule({ url: '/shop/es/search/sales', method: 'post', data: { keyword: 'A' } })
302
+ */
303
+ this.handleSalesSearchModule = async ({ data, config }) => {
304
+ return this.handleSalesSearchRequest("single", "/shop/es/search/sales", data, config);
305
+ };
306
+ /**
307
+ * 处理 sales 聚合搜索:请求透传后端,仅订阅 sales 分组的已返回订单号。
308
+ *
309
+ * @example
310
+ * await this.handleSalesSearchAggregate({ url: '/shop/es/search', method: 'post', data: { modules: [] } })
311
+ */
312
+ this.handleSalesSearchAggregate = async ({ data, config }) => {
313
+ return this.handleSalesSearchRequest("aggregate", "/shop/es/search", data, config);
314
+ };
315
+ /**
316
+ * 取消 sales 搜索订阅。
317
+ *
318
+ * @example
319
+ * await this.handleUnsubscribeSalesSearch({ data: { subscriberId: 'global-search-order' } } as any)
320
+ */
321
+ this.handleUnsubscribeSalesSearch = async ({ data }) => {
322
+ const { subscriberId } = data || {};
323
+ if (subscriberId) {
324
+ this.salesSearchSubscribers.delete(subscriberId);
325
+ this.logInfo("handleUnsubscribeSalesSearch: 已移除订阅者", {
326
+ subscriberId,
327
+ remaining: this.salesSearchSubscribers.size
328
+ });
329
+ }
330
+ return { code: 200, message: "ok", status: true };
331
+ };
295
332
  /**
296
333
  * 日历(compact_fields)场景下要直接在 SSE 层排除的订单类型:
297
334
  * 这些类型不会出现在日历上,拉取它们只会浪费带宽并增加前端过滤成本。
@@ -488,6 +525,54 @@ var Server = class {
488
525
  title: "handleOrderCheckout"
489
526
  });
490
527
  };
528
+ this.handleLocalPrintOrder = async ({ data }) => {
529
+ try {
530
+ const inputOrder = (data == null ? void 0 : data.order) && typeof data.order === "object" ? data.order : data;
531
+ if (!inputOrder || typeof inputOrder !== "object") {
532
+ return {
533
+ code: 400,
534
+ status: false,
535
+ message: "订单数据不能为空",
536
+ data: { printed: false, order: null }
537
+ };
538
+ }
539
+ const checkoutData = await this.ensureCheckoutOrderNumbers(
540
+ {
541
+ ...inputOrder,
542
+ small_ticket_data_flag: 1
543
+ },
544
+ "handleLocalPrintOrder"
545
+ );
546
+ const printableOrder = {
547
+ ...checkoutData,
548
+ need_sync: checkoutData.need_sync ?? 1
549
+ };
550
+ const printResult = await this.dispatchLocalReceiptPrint({
551
+ checkoutData,
552
+ order: printableOrder,
553
+ response: null,
554
+ requireFullyPaid: false
555
+ });
556
+ return {
557
+ code: 200,
558
+ status: true,
559
+ message: "",
560
+ data: {
561
+ printed: printResult.printed,
562
+ order: printResult.order
563
+ }
564
+ };
565
+ } catch (error) {
566
+ const message = error instanceof Error ? error.message : String(error);
567
+ this.logError("handleLocalPrintOrder: 本地打印小票失败", { error: message });
568
+ return {
569
+ code: 500,
570
+ status: false,
571
+ message,
572
+ data: { printed: false, order: null }
573
+ };
574
+ }
575
+ };
491
576
  this.handleOrderSalesDetail = async ({ url, data, path }) => {
492
577
  var _a;
493
578
  const requestPath = this.parseRequestPath(url, path);
@@ -934,6 +1019,7 @@ var Server = class {
934
1019
  moduleConfigs
935
1020
  });
936
1021
  this.registerServerRoutes();
1022
+ this.registerDeviceTaskActions();
937
1023
  const registeredModules = await this.registerModules(moduleConfigs);
938
1024
  if (autoPreload) {
939
1025
  await this.preloadModulesData(registeredModules, options);
@@ -949,10 +1035,11 @@ var Server = class {
949
1035
  this.core.effects.on(import_types.FloorPlanHooks.onFloorPlansChanged, () => {
950
1036
  void this.recomputeAndNotifyFloorPlanQuery();
951
1037
  });
952
- this.core.effects.on(import_types3.OrderHooks.onOrdersChanged, () => {
1038
+ this.core.effects.on(import_types3.OrderHooks.onOrdersChanged, (payload) => {
953
1039
  this.recomputeAndNotifyOrderQuery();
954
1040
  this.recomputeAndNotifyBookingQuery();
955
1041
  this.syncBookingRemoteCacheFromOrderChanges();
1042
+ this.notifySalesSearchSubscribers(payload);
956
1043
  });
957
1044
  const duration = Date.now() - startTime;
958
1045
  this.logInfo("Server 初始化完成", {
@@ -961,6 +1048,114 @@ var Server = class {
961
1048
  });
962
1049
  return registeredModules;
963
1050
  }
1051
+ registerDeviceTaskActions() {
1052
+ if (this.deviceTaskActionsRegistered)
1053
+ return;
1054
+ const deviceTask = this.getDeviceTaskPlugin();
1055
+ if (!(deviceTask == null ? void 0 : deviceTask.registerAction)) {
1056
+ this.logWarning("registerDeviceTaskActions: deviceTask 插件不可用");
1057
+ return;
1058
+ }
1059
+ const registeredActions = new Set(
1060
+ typeof deviceTask.getActions === "function" ? (deviceTask.getActions() || []).map((action) => action == null ? void 0 : action.action).filter(Boolean) : []
1061
+ );
1062
+ const register = (definition) => {
1063
+ var _a;
1064
+ if (registeredActions.has(definition.action))
1065
+ return;
1066
+ (_a = deviceTask.registerAction) == null ? void 0 : _a.call(deviceTask, definition);
1067
+ registeredActions.add(definition.action);
1068
+ };
1069
+ register({
1070
+ action: "sync_sales",
1071
+ name: "同步订单",
1072
+ validate: (payload) => (payload == null ? void 0 : payload.backendPath) && (payload == null ? void 0 : payload.data) ? null : "缺少 backendPath 或 data",
1073
+ handler: (ctx) => this.handleSyncSalesTask(ctx)
1074
+ });
1075
+ this.deviceTaskActionsRegistered = true;
1076
+ this.logInfo("DeviceTask actions 已注册", {
1077
+ actions: ["sync_sales"]
1078
+ });
1079
+ }
1080
+ async handleSyncSalesTask(ctx) {
1081
+ var _a, _b, _c;
1082
+ const payload = ((_a = ctx.task) == null ? void 0 : _a.payload) || {};
1083
+ const backendPath = payload.backendPath;
1084
+ const data = payload.data;
1085
+ const title = payload.title || "sync_sales";
1086
+ if (!backendPath || !data) {
1087
+ return this.taskFail("INVALID_PAYLOAD", "缺少 backendPath 或 data");
1088
+ }
1089
+ if (!((_b = this.app) == null ? void 0 : _b.request)) {
1090
+ this.logError(`${title}: sync_sales app.request 不可用`);
1091
+ return this.taskTimeout("app.request 不可用");
1092
+ }
1093
+ try {
1094
+ const response = await this.app.request.post("/shop/order/sales/checkout", data, {
1095
+ isShopApi: true,
1096
+ customToast: () => {
1097
+ }
1098
+ });
1099
+ if (this.isCheckoutResponseRejected(response)) {
1100
+ const message = (response == null ? void 0 : response.message) || "后端明确拒绝 checkout";
1101
+ this.logError(`${title}: sync_sales 后端明确失败`, {
1102
+ backendPath,
1103
+ response
1104
+ });
1105
+ return this.taskFail("BACKEND_REJECTED", message, response);
1106
+ }
1107
+ 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) {
1117
+ await this.order.upsertOrdersFromRemote([syncedOrder]);
1118
+ this.logInfo(`${title}: sync_sales 订单已同步到本地`, {
1119
+ order_id: fresh.order_id,
1120
+ external_sale_number: fresh.external_sale_number,
1121
+ order_number: fresh.order_number
1122
+ });
1123
+ } else {
1124
+ this.logWarning(`${title}: sync_sales Order 模块未注册`, {
1125
+ backendPath,
1126
+ order_id: fresh.order_id
1127
+ });
1128
+ }
1129
+ if (this.shouldPrintSyncedOrder({ checkoutData: data, syncedOrder })) {
1130
+ await this.dispatchPrintOtherReceiptTask({
1131
+ checkoutData: data,
1132
+ syncedOrder,
1133
+ response,
1134
+ deviceId: (_c = ctx.task) == null ? void 0 : _c.device_id
1135
+ });
1136
+ }
1137
+ return this.taskOk({
1138
+ order: syncedOrder,
1139
+ response: this.normalizeCheckoutResponse(response)
1140
+ });
1141
+ } catch (error) {
1142
+ const backendError = this.extractBackendErrorResponse(error);
1143
+ if (backendError) {
1144
+ const message = (backendError == null ? void 0 : backendError.message) || "后端明确拒绝 checkout";
1145
+ this.logError(`${title}: sync_sales 后端明确失败`, {
1146
+ backendPath,
1147
+ backendError
1148
+ });
1149
+ return this.taskFail("BACKEND_REJECTED", message, backendError);
1150
+ }
1151
+ const errorMessage = error instanceof Error ? error.message : String(error);
1152
+ this.logError(`${title}: sync_sales 请求未明确成功`, {
1153
+ backendPath,
1154
+ error: errorMessage
1155
+ });
1156
+ return this.taskTimeout(errorMessage);
1157
+ }
1158
+ }
964
1159
  /**
965
1160
  * 将普通层 QuotationModule 的报价单计算能力桥接到 Server Products 模块。
966
1161
  */
@@ -1264,6 +1459,26 @@ var Server = class {
1264
1459
  path: "/shop/order/v2/list/unsubscribe",
1265
1460
  handler: this.handleUnsubscribeOrderQuery.bind(this)
1266
1461
  },
1462
+ {
1463
+ method: "post",
1464
+ path: "/shop/es/search/sales",
1465
+ handler: this.handleSalesSearchModule.bind(this)
1466
+ },
1467
+ {
1468
+ method: "post",
1469
+ path: "/shop/es/search/sales/unsubscribe",
1470
+ handler: this.handleUnsubscribeSalesSearch.bind(this)
1471
+ },
1472
+ {
1473
+ method: "post",
1474
+ path: "/shop/es/search",
1475
+ handler: this.handleSalesSearchAggregate.bind(this)
1476
+ },
1477
+ {
1478
+ method: "post",
1479
+ path: "/shop/es/search/unsubscribe",
1480
+ handler: this.handleUnsubscribeSalesSearch.bind(this)
1481
+ },
1267
1482
  {
1268
1483
  method: "get",
1269
1484
  path: "/shop/schedule/booking",
@@ -1296,8 +1511,13 @@ var Server = class {
1296
1511
  },
1297
1512
  {
1298
1513
  method: "post",
1299
- path: "/shop/order/checkout",
1514
+ path: "/order/checkout",
1300
1515
  handler: this.handleOrderCheckout.bind(this)
1516
+ },
1517
+ {
1518
+ method: "post",
1519
+ path: "/local/print-order",
1520
+ handler: this.handleLocalPrintOrder.bind(this)
1301
1521
  }
1302
1522
  ]);
1303
1523
  this.registerPrefixRoutes([
@@ -1344,6 +1564,162 @@ var Server = class {
1344
1564
  });
1345
1565
  }
1346
1566
  }
1567
+ /**
1568
+ * 执行 sales 搜索并登记可见订单号。
1569
+ * 搜索参数完全透传后端,OS 不做过滤、筛选、排序。
1570
+ *
1571
+ * @example
1572
+ * const result = await this.handleSalesSearchRequest('single', '/shop/es/search/sales', { keyword: '1001' }, {})
1573
+ */
1574
+ async handleSalesSearchRequest(kind, backendPath, data, config) {
1575
+ const queryPayload = data && typeof data === "object" ? { ...data } : {};
1576
+ const result = await this.fetchSalesSearchFromAPI(backendPath, queryPayload);
1577
+ const { callback, subscriberId, resetVisibleOrderIds } = config || {};
1578
+ if (subscriberId && typeof callback === "function") {
1579
+ const contextSignature = this.buildSalesSearchSignature(kind, queryPayload);
1580
+ const existing = this.salesSearchSubscribers.get(subscriberId);
1581
+ const shouldReset = resetVisibleOrderIds === true || !existing || existing.kind !== kind || existing.contextSignature !== contextSignature;
1582
+ const visibleOrderIds = shouldReset ? /* @__PURE__ */ new Set() : new Set(existing.visibleOrderIds);
1583
+ for (const orderId of this.extractSalesSearchOrderIds(kind, result)) {
1584
+ visibleOrderIds.add(orderId);
1585
+ }
1586
+ this.salesSearchSubscribers.set(subscriberId, {
1587
+ callback,
1588
+ kind,
1589
+ contextSignature,
1590
+ visibleOrderIds,
1591
+ lastResponseData: this.extractSalesSearchResponseData(result)
1592
+ });
1593
+ this.logInfo("handleSalesSearchRequest: 已注册/更新订阅者", {
1594
+ subscriberId,
1595
+ kind,
1596
+ shouldReset,
1597
+ visibleCount: visibleOrderIds.size
1598
+ });
1599
+ }
1600
+ return result;
1601
+ }
1602
+ /**
1603
+ * 透传调用后端 sales 搜索接口。
1604
+ *
1605
+ * @example
1606
+ * const res = await this.fetchSalesSearchFromAPI('/shop/es/search/sales', { keyword: '1001' })
1607
+ */
1608
+ async fetchSalesSearchFromAPI(backendPath, data) {
1609
+ var _a;
1610
+ if (!((_a = this.app) == null ? void 0 : _a.request)) {
1611
+ this.logError("fetchSalesSearchFromAPI: app.request 不可用", { backendPath });
1612
+ return {
1613
+ code: 500,
1614
+ message: "app.request 不可用",
1615
+ data: backendPath === "/shop/es/search" ? { results: [] } : { list: [], count: 0 },
1616
+ status: false
1617
+ };
1618
+ }
1619
+ try {
1620
+ const response = await this.app.request.post(backendPath, data, {
1621
+ isShopApi: true
1622
+ });
1623
+ const payload = (response == null ? void 0 : response.data) ?? response;
1624
+ return {
1625
+ code: (response == null ? void 0 : response.code) ?? 200,
1626
+ status: (response == null ? void 0 : response.status) ?? true,
1627
+ message: (response == null ? void 0 : response.message) ?? "",
1628
+ data: payload
1629
+ };
1630
+ } catch (error) {
1631
+ const errorMessage = error instanceof Error ? error.message : String(error);
1632
+ this.logError("fetchSalesSearchFromAPI: 请求失败", {
1633
+ backendPath,
1634
+ error: errorMessage
1635
+ });
1636
+ return {
1637
+ code: 500,
1638
+ message: errorMessage,
1639
+ data: backendPath === "/shop/es/search" ? { results: [] } : { list: [], count: 0 },
1640
+ status: false
1641
+ };
1642
+ }
1643
+ }
1644
+ /**
1645
+ * 构建搜索订阅签名;页码变化不重置,可继续累计 visibleOrderIds。
1646
+ *
1647
+ * @example
1648
+ * const signature = this.buildSalesSearchSignature('single', { keyword: 'A', page: 2 })
1649
+ */
1650
+ buildSalesSearchSignature(kind, payload) {
1651
+ return this.stableSerialize({
1652
+ kind,
1653
+ payload: this.stripSalesSearchPageParams(payload)
1654
+ });
1655
+ }
1656
+ /**
1657
+ * 移除页码参数,保留 page size、keyword、filters、sort 等查询语义参数。
1658
+ *
1659
+ * @example
1660
+ * this.stripSalesSearchPageParams({ page: 2, per_page: 20, keyword: 'A' })
1661
+ */
1662
+ stripSalesSearchPageParams(value) {
1663
+ if (Array.isArray(value)) {
1664
+ return value.map((item) => this.stripSalesSearchPageParams(item));
1665
+ }
1666
+ if (!value || typeof value !== "object")
1667
+ return value;
1668
+ const next = {};
1669
+ for (const [key, item] of Object.entries(value)) {
1670
+ if (key === "page" || key === "skip")
1671
+ continue;
1672
+ next[key] = this.stripSalesSearchPageParams(item);
1673
+ }
1674
+ return next;
1675
+ }
1676
+ /**
1677
+ * 提取响应 data,兼容 OS 包装结构与后端直接响应结构。
1678
+ *
1679
+ * @example
1680
+ * const data = this.extractSalesSearchResponseData(result)
1681
+ */
1682
+ extractSalesSearchResponseData(result) {
1683
+ return (result == null ? void 0 : result.data) ?? result;
1684
+ }
1685
+ /**
1686
+ * 从搜索响应中提取 sales 命中的订单号。
1687
+ *
1688
+ * @example
1689
+ * const ids = this.extractSalesSearchOrderIds('single', result)
1690
+ */
1691
+ extractSalesSearchOrderIds(kind, result) {
1692
+ var _a;
1693
+ const data = this.extractSalesSearchResponseData(result);
1694
+ const list = kind === "aggregate" ? (_a = this.findSalesSearchAggregateGroup(data)) == null ? void 0 : _a.list : data == null ? void 0 : data.list;
1695
+ if (!Array.isArray(list))
1696
+ return [];
1697
+ return list.map((item) => this.getSalesSearchOrderId(item)).filter((id) => !!id);
1698
+ }
1699
+ /**
1700
+ * 查找聚合搜索响应中的 sales 分组。
1701
+ *
1702
+ * @example
1703
+ * const group = this.findSalesSearchAggregateGroup({ results: [{ module: 'sales' }] })
1704
+ */
1705
+ findSalesSearchAggregateGroup(data) {
1706
+ const results = Array.isArray(data == null ? void 0 : data.results) ? data.results : [];
1707
+ return results.find((item) => (item == null ? void 0 : item.module) === "sales") || null;
1708
+ }
1709
+ /**
1710
+ * 从订单或搜索命中项中取订单号。
1711
+ *
1712
+ * @example
1713
+ * const id = this.getSalesSearchOrderId({ order_id: 1001 })
1714
+ */
1715
+ getSalesSearchOrderId(order) {
1716
+ if (!order || typeof order !== "object")
1717
+ return null;
1718
+ const raw = order.order_id ?? order.id;
1719
+ if (raw === void 0 || raw === null || raw === "")
1720
+ return null;
1721
+ return String(raw);
1722
+ }
1347
1723
  /**
1348
1724
  * 从查询值中提取 YYYY-MM-DD 日期串。
1349
1725
  *
@@ -1784,8 +2160,203 @@ var Server = class {
1784
2160
  };
1785
2161
  }
1786
2162
  }
1787
- async handleOrderCheckoutSubmit(params) {
2163
+ getDeviceTaskPlugin() {
2164
+ var _a, _b;
2165
+ return ((_b = (_a = this.app) == null ? void 0 : _a.getPlugin) == null ? void 0 : _b.call(_a, "deviceTask")) || null;
2166
+ }
2167
+ getIdGeneratorPlugin() {
2168
+ var _a, _b;
2169
+ return ((_b = (_a = this.app) == null ? void 0 : _a.getPlugin) == null ? void 0 : _b.call(_a, "idGenerator")) || null;
2170
+ }
2171
+ getAppData(key) {
2172
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v;
2173
+ const getData = (_b = (_a = this.app) == null ? void 0 : _a.getData) == null ? void 0 : _b.call(_a);
2174
+ if (typeof getData === "function")
2175
+ return getData(key);
2176
+ const directValue = (_d = (_c = this.app) == null ? void 0 : _c.getData) == null ? void 0 : _d.call(_c, key);
2177
+ if (directValue !== void 0)
2178
+ return directValue;
2179
+ const coreData = ((_i = (_g = (_f = (_e = this.app) == null ? void 0 : _e.models) == null ? void 0 : _f.getStore) == null ? void 0 : (_h = _g.call(_f)).getDataByModel) == null ? void 0 : _i.call(_h, "core", "core")) || ((_o = (_m = (_l = (_k = (_j = this.app) == null ? void 0 : _j.data) == null ? void 0 : _k.store) == null ? void 0 : _l.getStore) == null ? void 0 : (_n = _m.call(_l)).getDataByModel) == null ? void 0 : _o.call(_n, "core", "core")) || ((_v = (_u = (_s = (_r = (_q = (_p = this.app) == null ? void 0 : _p.data) == null ? void 0 : _q.store) == null ? void 0 : _r.getStore) == null ? void 0 : (_t = _s.call(_r)).getDataByModel) == null ? void 0 : _u.call(_t, "core")) == null ? void 0 : _v.core);
2180
+ return coreData == null ? void 0 : coreData[key];
2181
+ }
2182
+ getSmallTicketShopInfo() {
2183
+ const shopInfo = this.getAppData("shop_info") || {};
2184
+ return {
2185
+ ...shopInfo,
2186
+ currency_symbol: shopInfo.currency_symbol || this.getAppData("shop_symbol") || this.getAppData("currency_symbol"),
2187
+ currency_code: shopInfo.currency_code || this.getAppData("shop_currency_code") || this.getAppData("currency_code"),
2188
+ tax_title: shopInfo.tax_title || this.getAppData("tax_title"),
2189
+ tax_country_code: shopInfo.tax_country_code || this.getAppData("tax_country_code"),
2190
+ is_price_include_tax: shopInfo.is_price_include_tax ?? this.getAppData("is_price_include_tax")
2191
+ };
2192
+ }
2193
+ taskOk(result) {
2194
+ return { status: "success", result };
2195
+ }
2196
+ taskFail(code, message, result) {
2197
+ return {
2198
+ status: "failed",
2199
+ error: { code, message },
2200
+ ...result !== void 0 ? { result } : {}
2201
+ };
2202
+ }
2203
+ taskTimeout(message) {
2204
+ return {
2205
+ status: "timeout",
2206
+ error: { code: "TIMEOUT", message }
2207
+ };
2208
+ }
2209
+ resolveCheckoutTaskDeviceId(_data) {
2210
+ return this.getAppData("device_id") || 0;
2211
+ }
2212
+ buildCheckoutTaskIdempotencyKey(data) {
2213
+ 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);
2214
+ if (identity === void 0 || identity === null || identity === "")
2215
+ return void 0;
2216
+ return `sync_sales:${identity}`;
2217
+ }
2218
+ async ensureCheckoutOrderNumbers(data, title) {
2219
+ if (!data || typeof data !== "object")
2220
+ return data;
2221
+ const next = { ...data };
2222
+ const needsShopOrderNumber = next.shop_order_number === void 0 || next.shop_order_number === null || next.shop_order_number === "";
2223
+ const needsShopFullOrderNumber = next.shop_full_order_number === void 0 || next.shop_full_order_number === null || next.shop_full_order_number === "";
2224
+ if (!needsShopOrderNumber && !needsShopFullOrderNumber)
2225
+ return next;
2226
+ const idGenerator = this.getIdGeneratorPlugin();
2227
+ if (!idGenerator) {
2228
+ this.logWarning(`${title}: idGenerator 插件不可用,无法生成订单号`, {
2229
+ needsShopOrderNumber,
2230
+ needsShopFullOrderNumber
2231
+ });
2232
+ return next;
2233
+ }
2234
+ try {
2235
+ if (needsShopOrderNumber && idGenerator.generateShopOrderNumber) {
2236
+ next.shop_order_number = await idGenerator.generateShopOrderNumber({
2237
+ biz: next.business_code || "ticket"
2238
+ });
2239
+ }
2240
+ if (needsShopFullOrderNumber && idGenerator.generateReceiptId) {
2241
+ next.shop_full_order_number = await idGenerator.generateReceiptId({
2242
+ biz: next.business_code || "ticket"
2243
+ });
2244
+ }
2245
+ this.logInfo(`${title}: checkout 订单号已准备`, {
2246
+ shop_order_number: next.shop_order_number,
2247
+ shop_full_order_number: next.shop_full_order_number
2248
+ });
2249
+ } catch (error) {
2250
+ this.logError(`${title}: 生成 checkout 订单号失败`, {
2251
+ error: error instanceof Error ? error.message : String(error)
2252
+ });
2253
+ }
2254
+ return next;
2255
+ }
2256
+ async dispatchCheckoutSyncTask(params) {
2257
+ var _a, _b, _c;
2258
+ this.registerDeviceTaskActions();
2259
+ const deviceTask = this.getDeviceTaskPlugin();
2260
+ const debugDeviceId = this.resolveCheckoutTaskDeviceId(params.data);
2261
+ const debugIdempotencyKey = this.buildCheckoutTaskIdempotencyKey(params.data);
2262
+ if (!(deviceTask == null ? void 0 : deviceTask.dispatch)) {
2263
+ this.logError(`${params.title}: deviceTask.dispatch 不可用`);
2264
+ return;
2265
+ }
2266
+ try {
2267
+ const result = await deviceTask.dispatch({
2268
+ action: "sync_sales",
2269
+ device_id: debugDeviceId,
2270
+ payload: {
2271
+ backendPath: params.backendPath,
2272
+ data: params.data,
2273
+ title: params.title
2274
+ },
2275
+ retry_limit: 5,
2276
+ idempotency_key: debugIdempotencyKey,
2277
+ name: "同步订单",
2278
+ source: "server",
2279
+ source_type: "order",
2280
+ 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)
2281
+ });
2282
+ this.logInfo(`${params.title}: sync_sales 任务已派发`, {
2283
+ uuid: result == null ? void 0 : result.uuid,
2284
+ status: result == null ? void 0 : result.status,
2285
+ reused: result == null ? void 0 : result.reused
2286
+ });
2287
+ } catch (error) {
2288
+ this.logError(`${params.title}: 派发 sync_sales 任务失败`, {
2289
+ error: error instanceof Error ? error.message : String(error)
2290
+ });
2291
+ }
2292
+ }
2293
+ async dispatchPrintOtherReceiptTask(params) {
2294
+ var _a, _b, _c, _d, _e;
2295
+ const deviceTask = this.getDeviceTaskPlugin();
2296
+ if (!(deviceTask == null ? void 0 : deviceTask.dispatch)) {
2297
+ this.logWarning("dispatchPrintOtherReceiptTask: deviceTask.dispatch 不可用");
2298
+ return;
2299
+ }
2300
+ try {
2301
+ const printIdentity = this.getPrintOrderIdentity(params.syncedOrder);
2302
+ await deviceTask.dispatch({
2303
+ action: "print_all",
2304
+ device_id: params.deviceId ?? this.resolveCheckoutTaskDeviceId(params.checkoutData),
2305
+ payload: {
2306
+ type: params.receiptOnly ? "0" : "99",
2307
+ data: params.receiptOnly ? {
2308
+ order_id: printIdentity,
2309
+ small_ticket_data: (_b = (_a = params.syncedOrder) == null ? void 0 : _a.payment_info) == null ? void 0 : _b.small_ticket_data
2310
+ } : {
2311
+ order_id: printIdentity,
2312
+ machine_code_print_info: (_d = (_c = params.syncedOrder) == null ? void 0 : _c.payment_info) == null ? void 0 : _d.machine_code_print_info,
2313
+ machine_code_print_info_v2: (_e = params.syncedOrder) == null ? void 0 : _e.machine_code_print_info_v2,
2314
+ skip_receipt: true
2315
+ }
2316
+ },
2317
+ idempotency_key: this.buildPrintOtherReceiptIdempotencyKey(params.syncedOrder, {
2318
+ receiptOnly: params.receiptOnly
2319
+ }),
2320
+ name: "打印转发",
2321
+ source: "server",
2322
+ source_type: "order",
2323
+ source_id: printIdentity
2324
+ });
2325
+ } catch (error) {
2326
+ this.logError("dispatchPrintOtherReceiptTask: 派发失败", {
2327
+ error: error instanceof Error ? error.message : String(error)
2328
+ });
2329
+ }
2330
+ }
2331
+ buildPrintOtherReceiptIdempotencyKey(order, options) {
2332
+ const identity = (order == null ? void 0 : order.external_sale_number) || (order == null ? void 0 : order.shop_order_number) || (order == null ? void 0 : order.shop_full_order_number) || (order == null ? void 0 : order.order_id);
2333
+ if (identity === void 0 || identity === null || identity === "")
2334
+ return void 0;
2335
+ return `${(options == null ? void 0 : options.receiptOnly) ? "print_receipt" : "print_voucher"}:${identity}`;
2336
+ }
2337
+ getPrintOrderIdentity(order) {
2338
+ return (order == null ? void 0 : order.order_id) || (order == null ? void 0 : order.external_sale_number) || (order == null ? void 0 : order.shop_order_number) || (order == null ? void 0 : order.shop_full_order_number);
2339
+ }
2340
+ async dispatchLocalReceiptPrint(params) {
1788
2341
  var _a;
2342
+ if (params.requireFullyPaid && !this.isSalesOrderFullyPaid(params.order)) {
2343
+ return { printed: false, order: params.order };
2344
+ }
2345
+ const printableOrder = await this.withLocalSmallTicketData(params.order, {
2346
+ requireFullyPaid: params.requireFullyPaid
2347
+ });
2348
+ if (!(0, import_small_ticket.hasSmallTicketData)((_a = printableOrder.payment_info) == null ? void 0 : _a.small_ticket_data)) {
2349
+ return { printed: false, order: printableOrder };
2350
+ }
2351
+ await this.dispatchPrintOtherReceiptTask({
2352
+ checkoutData: params.checkoutData,
2353
+ syncedOrder: printableOrder,
2354
+ response: params.response,
2355
+ receiptOnly: true
2356
+ });
2357
+ return { printed: true, order: printableOrder };
2358
+ }
2359
+ async handleOrderCheckoutSubmit(params) {
1789
2360
  const { backendPath, data, title } = params;
1790
2361
  this.logInfo(`${title}: 开始处理`, {
1791
2362
  backendPath,
@@ -1793,54 +2364,34 @@ var Server = class {
1793
2364
  external_sale_number: data == null ? void 0 : data.external_sale_number,
1794
2365
  order_number: data == null ? void 0 : data.order_number
1795
2366
  });
1796
- if (!((_a = this.app) == null ? void 0 : _a.request)) {
1797
- this.logError(`${title}: app.request 不可用`);
1798
- return this.handlePendingSyncCheckoutOrder({
1799
- backendPath,
1800
- data,
1801
- title,
1802
- reason: "app.request 不可用"
1803
- });
1804
- }
1805
- try {
1806
- const response = await this.app.request.post(backendPath, data, {
1807
- isShopApi: true,
1808
- customToast: () => {
1809
- }
1810
- });
1811
- const fresh = this.extractOrderDataFromCheckoutResponse(response);
1812
- if (fresh && this.order) {
1813
- const syncedOrder = { ...fresh, need_sync: 0 };
1814
- await this.order.upsertOrdersFromRemote([syncedOrder]);
1815
- this.logInfo(`${title}: 订单已同步到本地`, {
1816
- order_id: fresh.order_id,
1817
- external_sale_number: fresh.external_sale_number,
1818
- order_number: fresh.order_number
1819
- });
1820
- } else {
1821
- this.logWarning(`${title}: checkout 返回未包含可同步订单`, {
1822
- hasOrderModule: !!this.order,
1823
- backendPath
2367
+ const checkoutData = await this.ensureCheckoutOrderNumbers(data, title);
2368
+ const pendingResult = await this.handlePendingSyncCheckoutOrder({
2369
+ backendPath,
2370
+ data: checkoutData,
2371
+ title,
2372
+ reason: "checkout 已转入设备任务同步"
2373
+ });
2374
+ if ((pendingResult == null ? void 0 : pendingResult.status) === true) {
2375
+ const pendingOrder = pendingResult.data;
2376
+ if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData) && this.isSalesOrderFullyPaid(pendingOrder)) {
2377
+ await this.dispatchLocalReceiptPrint({
2378
+ checkoutData,
2379
+ order: pendingOrder,
2380
+ response: pendingResult,
2381
+ requireFullyPaid: true
1824
2382
  });
1825
2383
  }
1826
- return this.normalizeCheckoutResponse(response);
1827
- } catch (error) {
1828
- const errorMessage = error instanceof Error ? error.message : String(error);
1829
- this.logError(`${title}: 请求失败`, { backendPath, error: errorMessage });
1830
- const backendError = this.extractBackendErrorResponse(error);
1831
- if (backendError)
1832
- return backendError;
1833
- return this.handlePendingSyncCheckoutOrder({
2384
+ await this.dispatchCheckoutSyncTask({
1834
2385
  backendPath,
1835
- data,
1836
- title,
1837
- reason: errorMessage
2386
+ data: checkoutData,
2387
+ title
1838
2388
  });
1839
2389
  }
2390
+ return pendingResult;
1840
2391
  }
1841
2392
  async handlePendingSyncCheckoutOrder(params) {
1842
2393
  const { backendPath, data, title, reason } = params;
1843
- const pendingOrder = this.buildPendingSyncCheckoutOrder(data);
2394
+ const pendingOrder = await this.buildPendingSyncCheckoutOrder(data);
1844
2395
  if (!pendingOrder) {
1845
2396
  this.logError(`${title}: checkout 失败且订单缺少本地存储标识`, {
1846
2397
  backendPath,
@@ -1867,7 +2418,7 @@ var Server = class {
1867
2418
  }
1868
2419
  try {
1869
2420
  await this.order.upsertPendingSyncOrders([pendingOrder]);
1870
- this.logWarning(`${title}: 后端未明确报错,订单已写入本地待同步`, {
2421
+ this.logWarning(`${title}: 订单已写入本地待同步`, {
1871
2422
  backendPath,
1872
2423
  reason,
1873
2424
  order_id: pendingOrder.order_id,
@@ -1890,16 +2441,135 @@ var Server = class {
1890
2441
  return { code: 500, status: false, message: errorMessage, data: null };
1891
2442
  }
1892
2443
  }
1893
- buildPendingSyncCheckoutOrder(data) {
2444
+ async buildPendingSyncCheckoutOrder(data) {
1894
2445
  if (!data || typeof data !== "object")
1895
2446
  return null;
1896
2447
  const hasStorageKey = data.external_sale_number !== void 0 && data.external_sale_number !== null && data.external_sale_number !== "" ? true : data.order_id !== void 0 && data.order_id !== null && data.order_id !== "";
1897
2448
  if (!hasStorageKey)
1898
2449
  return null;
1899
- return {
1900
- ...data,
1901
- need_sync: 1
1902
- };
2450
+ return this.withLocalSmallTicketData(
2451
+ {
2452
+ ...data,
2453
+ need_sync: 1
2454
+ },
2455
+ { requireFullyPaid: true }
2456
+ );
2457
+ }
2458
+ shouldBuildSmallTicketData(order) {
2459
+ var _a;
2460
+ if (!order || typeof order !== "object")
2461
+ return false;
2462
+ if ((0, import_small_ticket.hasSmallTicketData)((_a = order.payment_info) == null ? void 0 : _a.small_ticket_data))
2463
+ return false;
2464
+ return Number(order.small_ticket_data_flag ?? order.smallTicketDataFlag ?? 0) === 1;
2465
+ }
2466
+ shouldPrintSyncedOrder(params) {
2467
+ if (this.hasPaymentStatus(params.syncedOrder)) {
2468
+ return this.isSalesOrderFullyPaid(params.syncedOrder);
2469
+ }
2470
+ return this.isSalesOrderFullyPaid(params.checkoutData);
2471
+ }
2472
+ hasPaymentStatus(order) {
2473
+ return (order == null ? void 0 : order.payment_status) !== void 0 && (order == null ? void 0 : order.payment_status) !== null && (order == null ? void 0 : order.payment_status) !== "";
2474
+ }
2475
+ isSalesOrderFullyPaid(order) {
2476
+ var _a, _b, _c;
2477
+ if (!order || typeof order !== "object")
2478
+ return false;
2479
+ const paymentStatus = String(order.payment_status || "").toLowerCase();
2480
+ if (paymentStatus === "paid" || paymentStatus === "finished")
2481
+ return true;
2482
+ if (paymentStatus === "partially_paid" || paymentStatus === "payment_processing" || paymentStatus === "pending" || paymentStatus === "unpaid") {
2483
+ return false;
2484
+ }
2485
+ const amountGap = ((_a = order.summary) == null ? void 0 : _a.amount_gap) ?? order.amount_gap;
2486
+ if (amountGap !== void 0 && amountGap !== null && amountGap !== "") {
2487
+ return this.toAmountNumber(amountGap) <= 0;
2488
+ }
2489
+ const paidAmount = this.sumPaidOrderPayments(order.payments);
2490
+ const targetAmount = this.toAmountNumber(
2491
+ ((_b = order.summary) == null ? void 0 : _b.expect_amount) ?? ((_c = order.summary) == null ? void 0 : _c.total_amount) ?? order.expect_amount ?? order.total_amount
2492
+ );
2493
+ if (targetAmount <= 0)
2494
+ return paidAmount > 0;
2495
+ return paidAmount >= targetAmount;
2496
+ }
2497
+ sumPaidOrderPayments(payments) {
2498
+ if (!Array.isArray(payments))
2499
+ return 0;
2500
+ return payments.reduce((sum, payment) => {
2501
+ const status = String((payment == null ? void 0 : payment.status) || "").toLowerCase();
2502
+ if (status === "voided" || status === "failed" || status === "cancelled")
2503
+ return sum;
2504
+ return sum + this.toAmountNumber((payment == null ? void 0 : payment.amount) ?? (payment == null ? void 0 : payment.origin_amount));
2505
+ }, 0);
2506
+ }
2507
+ toAmountNumber(value) {
2508
+ if (typeof value === "number")
2509
+ return Number.isFinite(value) ? value : 0;
2510
+ if (typeof value !== "string")
2511
+ return 0;
2512
+ const parsed = Number(value.replace(/[^\d.-]/g, ""));
2513
+ return Number.isFinite(parsed) ? parsed : 0;
2514
+ }
2515
+ async buildSmallTicketProductMap(order) {
2516
+ var _a;
2517
+ const products = Array.isArray(order == null ? void 0 : order.products) ? order.products : [];
2518
+ const productIds = Array.from(
2519
+ new Set(
2520
+ products.map((product) => (product == null ? void 0 : product.product_id) ?? (product == null ? void 0 : product.id)).filter((id) => id !== void 0 && id !== null && id !== "")
2521
+ )
2522
+ );
2523
+ if (!productIds.length || typeof ((_a = this.products) == null ? void 0 : _a.getProductById) !== "function")
2524
+ return {};
2525
+ const entries = await Promise.all(
2526
+ productIds.map(async (id) => {
2527
+ var _a2, _b;
2528
+ try {
2529
+ const product = await ((_b = (_a2 = this.products) == null ? void 0 : _a2.getProductById) == null ? void 0 : _b.call(_a2, Number(id)));
2530
+ return product ? [String(id), product] : null;
2531
+ } catch (error) {
2532
+ this.logWarning("buildSmallTicketProductMap: 查询本地商品失败", {
2533
+ product_id: id,
2534
+ error: error instanceof Error ? error.message : String(error)
2535
+ });
2536
+ return null;
2537
+ }
2538
+ })
2539
+ );
2540
+ return entries.reduce((map, entry) => {
2541
+ if (!entry)
2542
+ return map;
2543
+ const [id, product] = entry;
2544
+ map[id] = product;
2545
+ return map;
2546
+ }, {});
2547
+ }
2548
+ async withLocalSmallTicketData(order, options) {
2549
+ if (!this.shouldBuildSmallTicketData(order))
2550
+ return order;
2551
+ if ((options == null ? void 0 : options.requireFullyPaid) && !this.isSalesOrderFullyPaid(order))
2552
+ return order;
2553
+ try {
2554
+ const productMap = await this.buildSmallTicketProductMap(order);
2555
+ const smallTicketData = (0, import_small_ticket.buildSmallTicketData)({
2556
+ order,
2557
+ shopInfo: this.getSmallTicketShopInfo(),
2558
+ productMap
2559
+ });
2560
+ return {
2561
+ ...order,
2562
+ payment_info: {
2563
+ ...order.payment_info || {},
2564
+ small_ticket_data: smallTicketData
2565
+ }
2566
+ };
2567
+ } catch (error) {
2568
+ this.logError("withLocalSmallTicketData: 生成本地小票数据失败", {
2569
+ error: error instanceof Error ? error.message : String(error)
2570
+ });
2571
+ return order;
2572
+ }
1903
2573
  }
1904
2574
  /**
1905
2575
  * 解析 order_ids 入参,兼容 url query / data 字段、字符串(csv) / 数组两种形态。
@@ -2104,6 +2774,13 @@ var Server = class {
2104
2774
  data: response
2105
2775
  };
2106
2776
  }
2777
+ isCheckoutResponseRejected(response) {
2778
+ const normalized = this.normalizeCheckoutResponse(response);
2779
+ const isErrorCode = (normalized == null ? void 0 : normalized.code) !== void 0 && normalized.code !== 200 && normalized.code !== "200";
2780
+ const isErrorStatus = (normalized == null ? void 0 : normalized.status) === false || typeof (normalized == null ? void 0 : normalized.status) === "number" && normalized.status >= 400;
2781
+ const isErrorSuccess = (normalized == null ? void 0 : normalized.success) === false;
2782
+ return isErrorCode || isErrorStatus || isErrorSuccess;
2783
+ }
2107
2784
  extractBackendErrorResponse(error) {
2108
2785
  var _a, _b;
2109
2786
  const candidates = [
@@ -2515,6 +3192,101 @@ var Server = class {
2515
3192
  totalNotifyDurationMs: notifyEndAt - notifyStartAt
2516
3193
  });
2517
3194
  }
3195
+ /**
3196
+ * 订单变更后通知 sales 搜索订阅者。
3197
+ * 仅回传当前查询已返回订单号集合中的变更订单。
3198
+ *
3199
+ * @example
3200
+ * this.notifySalesSearchSubscribers({ list: [], changedOrders: [order], source: 'pubsub.bodyUpsert' })
3201
+ */
3202
+ notifySalesSearchSubscribers(payload) {
3203
+ if (this.salesSearchSubscribers.size === 0)
3204
+ return;
3205
+ const changedOrders = this.extractChangedOrdersFromPayload(payload);
3206
+ if (changedOrders.length === 0) {
3207
+ return;
3208
+ }
3209
+ for (const [subscriberId, subscriber] of this.salesSearchSubscribers.entries()) {
3210
+ try {
3211
+ const changedVisibleOrders = changedOrders.filter((order) => {
3212
+ const orderId = this.getSalesSearchOrderId(order);
3213
+ return !!orderId && subscriber.visibleOrderIds.has(orderId);
3214
+ });
3215
+ if (changedVisibleOrders.length === 0) {
3216
+ continue;
3217
+ }
3218
+ subscriber.callback(
3219
+ this.buildSalesSearchDeltaResponse(subscriber, changedVisibleOrders)
3220
+ );
3221
+ this.logInfo("notifySalesSearchSubscribers: 已推送 delta", {
3222
+ subscriberId,
3223
+ kind: subscriber.kind,
3224
+ count: changedVisibleOrders.length
3225
+ });
3226
+ } catch (error) {
3227
+ const errorMessage = error instanceof Error ? error.message : String(error);
3228
+ this.logError("notifySalesSearchSubscribers: 推送失败", {
3229
+ subscriberId,
3230
+ error: errorMessage
3231
+ });
3232
+ }
3233
+ }
3234
+ }
3235
+ /**
3236
+ * 从订单变更事件中提取明确 delta。
3237
+ *
3238
+ * @example
3239
+ * const list = this.extractChangedOrdersFromPayload(payload)
3240
+ */
3241
+ extractChangedOrdersFromPayload(payload) {
3242
+ if (!payload || Array.isArray(payload))
3243
+ return [];
3244
+ return Array.isArray(payload.changedOrders) ? payload.changedOrders : [];
3245
+ }
3246
+ /**
3247
+ * 构建与当前搜索接口一致的 delta 响应。
3248
+ *
3249
+ * @example
3250
+ * const response = this.buildSalesSearchDeltaResponse(subscriber, [order])
3251
+ */
3252
+ buildSalesSearchDeltaResponse(subscriber, changedOrders) {
3253
+ if (subscriber.kind === "aggregate") {
3254
+ return this.buildAggregateSalesSearchDeltaResponse(subscriber, changedOrders);
3255
+ }
3256
+ const data = subscriber.lastResponseData || {};
3257
+ return {
3258
+ code: 200,
3259
+ status: true,
3260
+ message: "",
3261
+ data: {
3262
+ ...data,
3263
+ list: changedOrders
3264
+ }
3265
+ };
3266
+ }
3267
+ /**
3268
+ * 构建聚合搜索接口的 sales 分组 delta 响应。
3269
+ *
3270
+ * @example
3271
+ * const response = this.buildAggregateSalesSearchDeltaResponse(subscriber, [order])
3272
+ */
3273
+ buildAggregateSalesSearchDeltaResponse(subscriber, changedOrders) {
3274
+ const data = subscriber.lastResponseData || {};
3275
+ const results = Array.isArray(data == null ? void 0 : data.results) ? data.results : [];
3276
+ const hasSalesGroup = results.some((item) => (item == null ? void 0 : item.module) === "sales");
3277
+ const nextResults = hasSalesGroup ? results.map(
3278
+ (item) => (item == null ? void 0 : item.module) === "sales" ? { ...item, list: changedOrders } : item
3279
+ ) : [{ module: "sales", list: changedOrders, count: changedOrders.length }];
3280
+ return {
3281
+ code: 200,
3282
+ status: true,
3283
+ message: "",
3284
+ data: {
3285
+ ...data,
3286
+ results: nextResults
3287
+ }
3288
+ };
3289
+ }
2518
3290
  /**
2519
3291
  * 预约数据变更后,遍历订阅者重新计算并通过 callback 推送
2520
3292
  */