@pisell/pisellos 2.2.205 → 2.2.207

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 (44) hide show
  1. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  2. package/dist/modules/OpenData/index.d.ts +1 -0
  3. package/dist/modules/OpenData/index.js +21 -16
  4. package/dist/modules/Order/index.d.ts +9 -0
  5. package/dist/modules/Order/index.js +230 -145
  6. package/dist/modules/Order/types.d.ts +10 -0
  7. package/dist/modules/Order/utils.js +7 -5
  8. package/dist/server/index.d.ts +136 -0
  9. package/dist/server/index.js +2055 -781
  10. package/dist/server/modules/order/index.d.ts +7 -0
  11. package/dist/server/modules/order/index.js +375 -337
  12. package/dist/server/modules/order/types.d.ts +15 -0
  13. package/dist/server/modules/order/types.js +8 -0
  14. package/dist/server/utils/small-ticket.d.ts +69 -0
  15. package/dist/server/utils/small-ticket.js +528 -0
  16. package/dist/solution/BaseSales/index.d.ts +4 -2
  17. package/dist/solution/BaseSales/index.js +248 -188
  18. package/dist/solution/BookingByStep/index.d.ts +1 -1
  19. package/dist/solution/BookingTicket/index.d.ts +8 -1
  20. package/dist/solution/BookingTicket/index.js +443 -263
  21. package/dist/solution/BookingTicket/types.d.ts +2 -1
  22. package/dist/solution/BookingTicket/types.js +3 -1
  23. package/lib/model/strategy/adapter/promotion/index.js +0 -49
  24. package/lib/modules/OpenData/index.d.ts +1 -0
  25. package/lib/modules/OpenData/index.js +6 -4
  26. package/lib/modules/Order/index.d.ts +9 -0
  27. package/lib/modules/Order/index.js +59 -3
  28. package/lib/modules/Order/types.d.ts +10 -0
  29. package/lib/modules/Order/utils.js +4 -3
  30. package/lib/server/index.d.ts +136 -0
  31. package/lib/server/index.js +823 -50
  32. package/lib/server/modules/order/index.d.ts +7 -0
  33. package/lib/server/modules/order/index.js +21 -7
  34. package/lib/server/modules/order/types.d.ts +15 -0
  35. package/lib/server/utils/small-ticket.d.ts +69 -0
  36. package/lib/server/utils/small-ticket.js +555 -0
  37. package/lib/solution/BaseSales/index.d.ts +4 -2
  38. package/lib/solution/BaseSales/index.js +47 -1
  39. package/lib/solution/BookingByStep/index.d.ts +1 -1
  40. package/lib/solution/BookingTicket/index.d.ts +8 -1
  41. package/lib/solution/BookingTicket/index.js +108 -1
  42. package/lib/solution/BookingTicket/types.d.ts +2 -1
  43. package/lib/solution/BookingTicket/types.js +5 -0
  44. 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,204 @@ 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.core.getPlugin("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
+ debugger;
2185
+ return {
2186
+ ...shopInfo,
2187
+ currency_symbol: shopInfo.currency_symbol || this.getAppData("shop_symbol") || this.getAppData("currency_symbol"),
2188
+ currency_code: shopInfo.currency_code || this.getAppData("shop_currency_code") || this.getAppData("currency_code"),
2189
+ tax_title: shopInfo.tax_title || this.getAppData("tax_title"),
2190
+ tax_country_code: shopInfo.tax_country_code || this.getAppData("tax_country_code"),
2191
+ is_price_include_tax: shopInfo.is_price_include_tax ?? this.getAppData("is_price_include_tax")
2192
+ };
2193
+ }
2194
+ taskOk(result) {
2195
+ return { status: "success", result };
2196
+ }
2197
+ taskFail(code, message, result) {
2198
+ return {
2199
+ status: "failed",
2200
+ error: { code, message },
2201
+ ...result !== void 0 ? { result } : {}
2202
+ };
2203
+ }
2204
+ taskTimeout(message) {
2205
+ return {
2206
+ status: "timeout",
2207
+ error: { code: "TIMEOUT", message }
2208
+ };
2209
+ }
2210
+ resolveCheckoutTaskDeviceId(_data) {
2211
+ return this.getAppData("device_id") || 0;
2212
+ }
2213
+ buildCheckoutTaskIdempotencyKey(data) {
2214
+ 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);
2215
+ if (identity === void 0 || identity === null || identity === "")
2216
+ return void 0;
2217
+ return `sync_sales:${identity}`;
2218
+ }
2219
+ async ensureCheckoutOrderNumbers(data, title) {
2220
+ if (!data || typeof data !== "object")
2221
+ return data;
2222
+ const next = { ...data };
2223
+ const needsShopOrderNumber = next.shop_order_number === void 0 || next.shop_order_number === null || next.shop_order_number === "";
2224
+ const needsShopFullOrderNumber = next.shop_full_order_number === void 0 || next.shop_full_order_number === null || next.shop_full_order_number === "";
2225
+ if (!needsShopOrderNumber && !needsShopFullOrderNumber)
2226
+ return next;
2227
+ const idGenerator = this.getIdGeneratorPlugin();
2228
+ if (!idGenerator) {
2229
+ this.logWarning(`${title}: idGenerator 插件不可用,无法生成订单号`, {
2230
+ needsShopOrderNumber,
2231
+ needsShopFullOrderNumber
2232
+ });
2233
+ return next;
2234
+ }
2235
+ try {
2236
+ if (needsShopOrderNumber && idGenerator.generateShopOrderNumber) {
2237
+ next.shop_order_number = await idGenerator.generateShopOrderNumber({
2238
+ biz: next.business_code || "ticket"
2239
+ });
2240
+ }
2241
+ if (needsShopFullOrderNumber && idGenerator.generateReceiptId) {
2242
+ next.shop_full_order_number = await idGenerator.generateReceiptId({
2243
+ biz: next.business_code || "ticket"
2244
+ });
2245
+ }
2246
+ this.logInfo(`${title}: checkout 订单号已准备`, {
2247
+ shop_order_number: next.shop_order_number,
2248
+ shop_full_order_number: next.shop_full_order_number
2249
+ });
2250
+ } catch (error) {
2251
+ this.logError(`${title}: 生成 checkout 订单号失败`, {
2252
+ error: error instanceof Error ? error.message : String(error)
2253
+ });
2254
+ }
2255
+ return next;
2256
+ }
2257
+ async dispatchCheckoutSyncTask(params) {
2258
+ var _a, _b, _c;
2259
+ this.registerDeviceTaskActions();
2260
+ const deviceTask = this.getDeviceTaskPlugin();
2261
+ const debugDeviceId = this.resolveCheckoutTaskDeviceId(params.data);
2262
+ const debugIdempotencyKey = this.buildCheckoutTaskIdempotencyKey(params.data);
2263
+ if (!(deviceTask == null ? void 0 : deviceTask.dispatch)) {
2264
+ this.logError(`${params.title}: deviceTask.dispatch 不可用`);
2265
+ return;
2266
+ }
2267
+ try {
2268
+ const result = await deviceTask.dispatch({
2269
+ action: "sync_sales",
2270
+ device_id: debugDeviceId,
2271
+ payload: {
2272
+ backendPath: params.backendPath,
2273
+ data: params.data,
2274
+ title: params.title
2275
+ },
2276
+ retry_limit: 5,
2277
+ idempotency_key: debugIdempotencyKey,
2278
+ name: "同步订单",
2279
+ source: "server",
2280
+ source_type: "order",
2281
+ 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)
2282
+ });
2283
+ this.logInfo(`${params.title}: sync_sales 任务已派发`, {
2284
+ uuid: result == null ? void 0 : result.uuid,
2285
+ status: result == null ? void 0 : result.status,
2286
+ reused: result == null ? void 0 : result.reused
2287
+ });
2288
+ } catch (error) {
2289
+ this.logError(`${params.title}: 派发 sync_sales 任务失败`, {
2290
+ error: error instanceof Error ? error.message : String(error)
2291
+ });
2292
+ }
2293
+ }
2294
+ async dispatchPrintOtherReceiptTask(params) {
2295
+ var _a, _b, _c, _d, _e;
2296
+ const deviceTask = this.getDeviceTaskPlugin();
2297
+ if (!(deviceTask == null ? void 0 : deviceTask.dispatch)) {
2298
+ this.logWarning("dispatchPrintOtherReceiptTask: deviceTask.dispatch 不可用");
2299
+ return;
2300
+ }
2301
+ try {
2302
+ const printIdentity = this.getPrintOrderIdentity(params.syncedOrder);
2303
+ await deviceTask.dispatch({
2304
+ action: "print_all",
2305
+ device_id: params.deviceId ?? this.resolveCheckoutTaskDeviceId(params.checkoutData),
2306
+ payload: {
2307
+ type: params.receiptOnly ? "0" : "99",
2308
+ data: params.receiptOnly ? {
2309
+ order_id: printIdentity,
2310
+ small_ticket_data: (_b = (_a = params.syncedOrder) == null ? void 0 : _a.payment_info) == null ? void 0 : _b.small_ticket_data
2311
+ } : {
2312
+ order_id: printIdentity,
2313
+ machine_code_print_info: (_d = (_c = params.syncedOrder) == null ? void 0 : _c.payment_info) == null ? void 0 : _d.machine_code_print_info,
2314
+ machine_code_print_info_v2: (_e = params.syncedOrder) == null ? void 0 : _e.machine_code_print_info_v2,
2315
+ skip_receipt: true
2316
+ }
2317
+ },
2318
+ idempotency_key: this.buildPrintOtherReceiptIdempotencyKey(params.syncedOrder, {
2319
+ receiptOnly: params.receiptOnly
2320
+ }),
2321
+ name: "打印转发",
2322
+ source: "server",
2323
+ source_type: "order",
2324
+ source_id: printIdentity
2325
+ });
2326
+ } catch (error) {
2327
+ this.logError("dispatchPrintOtherReceiptTask: 派发失败", {
2328
+ error: error instanceof Error ? error.message : String(error)
2329
+ });
2330
+ }
2331
+ }
2332
+ buildPrintOtherReceiptIdempotencyKey(order, options) {
2333
+ 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);
2334
+ if (identity === void 0 || identity === null || identity === "")
2335
+ return void 0;
2336
+ return `${(options == null ? void 0 : options.receiptOnly) ? "print_receipt" : "print_voucher"}:${identity}`;
2337
+ }
2338
+ getPrintOrderIdentity(order) {
2339
+ 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);
2340
+ }
2341
+ async dispatchLocalReceiptPrint(params) {
1788
2342
  var _a;
2343
+ if (params.requireFullyPaid && !this.isSalesOrderFullyPaid(params.order)) {
2344
+ return { printed: false, order: params.order };
2345
+ }
2346
+ const printableOrder = await this.withLocalSmallTicketData(params.order, {
2347
+ requireFullyPaid: params.requireFullyPaid
2348
+ });
2349
+ if (!(0, import_small_ticket.hasSmallTicketData)((_a = printableOrder.payment_info) == null ? void 0 : _a.small_ticket_data)) {
2350
+ return { printed: false, order: printableOrder };
2351
+ }
2352
+ await this.dispatchPrintOtherReceiptTask({
2353
+ checkoutData: params.checkoutData,
2354
+ syncedOrder: printableOrder,
2355
+ response: params.response,
2356
+ receiptOnly: true
2357
+ });
2358
+ return { printed: true, order: printableOrder };
2359
+ }
2360
+ async handleOrderCheckoutSubmit(params) {
1789
2361
  const { backendPath, data, title } = params;
1790
2362
  this.logInfo(`${title}: 开始处理`, {
1791
2363
  backendPath,
@@ -1793,54 +2365,34 @@ var Server = class {
1793
2365
  external_sale_number: data == null ? void 0 : data.external_sale_number,
1794
2366
  order_number: data == null ? void 0 : data.order_number
1795
2367
  });
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
2368
+ const checkoutData = await this.ensureCheckoutOrderNumbers(data, title);
2369
+ const pendingResult = await this.handlePendingSyncCheckoutOrder({
2370
+ backendPath,
2371
+ data: checkoutData,
2372
+ title,
2373
+ reason: "checkout 已转入设备任务同步"
2374
+ });
2375
+ if ((pendingResult == null ? void 0 : pendingResult.status) === true) {
2376
+ const pendingOrder = pendingResult.data;
2377
+ if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData) && this.isSalesOrderFullyPaid(pendingOrder)) {
2378
+ await this.dispatchLocalReceiptPrint({
2379
+ checkoutData,
2380
+ order: pendingOrder,
2381
+ response: pendingResult,
2382
+ requireFullyPaid: true
1824
2383
  });
1825
2384
  }
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({
2385
+ await this.dispatchCheckoutSyncTask({
1834
2386
  backendPath,
1835
- data,
1836
- title,
1837
- reason: errorMessage
2387
+ data: checkoutData,
2388
+ title
1838
2389
  });
1839
2390
  }
2391
+ return pendingResult;
1840
2392
  }
1841
2393
  async handlePendingSyncCheckoutOrder(params) {
1842
2394
  const { backendPath, data, title, reason } = params;
1843
- const pendingOrder = this.buildPendingSyncCheckoutOrder(data);
2395
+ const pendingOrder = await this.buildPendingSyncCheckoutOrder(data);
1844
2396
  if (!pendingOrder) {
1845
2397
  this.logError(`${title}: checkout 失败且订单缺少本地存储标识`, {
1846
2398
  backendPath,
@@ -1867,7 +2419,7 @@ var Server = class {
1867
2419
  }
1868
2420
  try {
1869
2421
  await this.order.upsertPendingSyncOrders([pendingOrder]);
1870
- this.logWarning(`${title}: 后端未明确报错,订单已写入本地待同步`, {
2422
+ this.logWarning(`${title}: 订单已写入本地待同步`, {
1871
2423
  backendPath,
1872
2424
  reason,
1873
2425
  order_id: pendingOrder.order_id,
@@ -1890,16 +2442,135 @@ var Server = class {
1890
2442
  return { code: 500, status: false, message: errorMessage, data: null };
1891
2443
  }
1892
2444
  }
1893
- buildPendingSyncCheckoutOrder(data) {
2445
+ async buildPendingSyncCheckoutOrder(data) {
1894
2446
  if (!data || typeof data !== "object")
1895
2447
  return null;
1896
2448
  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
2449
  if (!hasStorageKey)
1898
2450
  return null;
1899
- return {
1900
- ...data,
1901
- need_sync: 1
1902
- };
2451
+ return this.withLocalSmallTicketData(
2452
+ {
2453
+ ...data,
2454
+ need_sync: 1
2455
+ },
2456
+ { requireFullyPaid: true }
2457
+ );
2458
+ }
2459
+ shouldBuildSmallTicketData(order) {
2460
+ var _a;
2461
+ if (!order || typeof order !== "object")
2462
+ return false;
2463
+ if ((0, import_small_ticket.hasSmallTicketData)((_a = order.payment_info) == null ? void 0 : _a.small_ticket_data))
2464
+ return false;
2465
+ return Number(order.small_ticket_data_flag ?? order.smallTicketDataFlag ?? 0) === 1;
2466
+ }
2467
+ shouldPrintSyncedOrder(params) {
2468
+ if (this.hasPaymentStatus(params.syncedOrder)) {
2469
+ return this.isSalesOrderFullyPaid(params.syncedOrder);
2470
+ }
2471
+ return this.isSalesOrderFullyPaid(params.checkoutData);
2472
+ }
2473
+ hasPaymentStatus(order) {
2474
+ 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) !== "";
2475
+ }
2476
+ isSalesOrderFullyPaid(order) {
2477
+ var _a, _b, _c;
2478
+ if (!order || typeof order !== "object")
2479
+ return false;
2480
+ const paymentStatus = String(order.payment_status || "").toLowerCase();
2481
+ if (paymentStatus === "paid" || paymentStatus === "finished")
2482
+ return true;
2483
+ if (paymentStatus === "partially_paid" || paymentStatus === "payment_processing" || paymentStatus === "pending" || paymentStatus === "unpaid") {
2484
+ return false;
2485
+ }
2486
+ const amountGap = ((_a = order.summary) == null ? void 0 : _a.amount_gap) ?? order.amount_gap;
2487
+ if (amountGap !== void 0 && amountGap !== null && amountGap !== "") {
2488
+ return this.toAmountNumber(amountGap) <= 0;
2489
+ }
2490
+ const paidAmount = this.sumPaidOrderPayments(order.payments);
2491
+ const targetAmount = this.toAmountNumber(
2492
+ ((_b = order.summary) == null ? void 0 : _b.expect_amount) ?? ((_c = order.summary) == null ? void 0 : _c.total_amount) ?? order.expect_amount ?? order.total_amount
2493
+ );
2494
+ if (targetAmount <= 0)
2495
+ return paidAmount > 0;
2496
+ return paidAmount >= targetAmount;
2497
+ }
2498
+ sumPaidOrderPayments(payments) {
2499
+ if (!Array.isArray(payments))
2500
+ return 0;
2501
+ return payments.reduce((sum, payment) => {
2502
+ const status = String((payment == null ? void 0 : payment.status) || "").toLowerCase();
2503
+ if (status === "voided" || status === "failed" || status === "cancelled")
2504
+ return sum;
2505
+ return sum + this.toAmountNumber((payment == null ? void 0 : payment.amount) ?? (payment == null ? void 0 : payment.origin_amount));
2506
+ }, 0);
2507
+ }
2508
+ toAmountNumber(value) {
2509
+ if (typeof value === "number")
2510
+ return Number.isFinite(value) ? value : 0;
2511
+ if (typeof value !== "string")
2512
+ return 0;
2513
+ const parsed = Number(value.replace(/[^\d.-]/g, ""));
2514
+ return Number.isFinite(parsed) ? parsed : 0;
2515
+ }
2516
+ async buildSmallTicketProductMap(order) {
2517
+ var _a;
2518
+ const products = Array.isArray(order == null ? void 0 : order.products) ? order.products : [];
2519
+ const productIds = Array.from(
2520
+ new Set(
2521
+ products.map((product) => (product == null ? void 0 : product.product_id) ?? (product == null ? void 0 : product.id)).filter((id) => id !== void 0 && id !== null && id !== "")
2522
+ )
2523
+ );
2524
+ if (!productIds.length || typeof ((_a = this.products) == null ? void 0 : _a.getProductById) !== "function")
2525
+ return {};
2526
+ const entries = await Promise.all(
2527
+ productIds.map(async (id) => {
2528
+ var _a2, _b;
2529
+ try {
2530
+ const product = await ((_b = (_a2 = this.products) == null ? void 0 : _a2.getProductById) == null ? void 0 : _b.call(_a2, Number(id)));
2531
+ return product ? [String(id), product] : null;
2532
+ } catch (error) {
2533
+ this.logWarning("buildSmallTicketProductMap: 查询本地商品失败", {
2534
+ product_id: id,
2535
+ error: error instanceof Error ? error.message : String(error)
2536
+ });
2537
+ return null;
2538
+ }
2539
+ })
2540
+ );
2541
+ return entries.reduce((map, entry) => {
2542
+ if (!entry)
2543
+ return map;
2544
+ const [id, product] = entry;
2545
+ map[id] = product;
2546
+ return map;
2547
+ }, {});
2548
+ }
2549
+ async withLocalSmallTicketData(order, options) {
2550
+ if (!this.shouldBuildSmallTicketData(order))
2551
+ return order;
2552
+ if ((options == null ? void 0 : options.requireFullyPaid) && !this.isSalesOrderFullyPaid(order))
2553
+ return order;
2554
+ try {
2555
+ const productMap = await this.buildSmallTicketProductMap(order);
2556
+ const smallTicketData = (0, import_small_ticket.buildSmallTicketData)({
2557
+ order,
2558
+ shopInfo: this.getSmallTicketShopInfo(),
2559
+ productMap
2560
+ });
2561
+ return {
2562
+ ...order,
2563
+ payment_info: {
2564
+ ...order.payment_info || {},
2565
+ small_ticket_data: smallTicketData
2566
+ }
2567
+ };
2568
+ } catch (error) {
2569
+ this.logError("withLocalSmallTicketData: 生成本地小票数据失败", {
2570
+ error: error instanceof Error ? error.message : String(error)
2571
+ });
2572
+ return order;
2573
+ }
1903
2574
  }
1904
2575
  /**
1905
2576
  * 解析 order_ids 入参,兼容 url query / data 字段、字符串(csv) / 数组两种形态。
@@ -2104,6 +2775,13 @@ var Server = class {
2104
2775
  data: response
2105
2776
  };
2106
2777
  }
2778
+ isCheckoutResponseRejected(response) {
2779
+ const normalized = this.normalizeCheckoutResponse(response);
2780
+ const isErrorCode = (normalized == null ? void 0 : normalized.code) !== void 0 && normalized.code !== 200 && normalized.code !== "200";
2781
+ const isErrorStatus = (normalized == null ? void 0 : normalized.status) === false || typeof (normalized == null ? void 0 : normalized.status) === "number" && normalized.status >= 400;
2782
+ const isErrorSuccess = (normalized == null ? void 0 : normalized.success) === false;
2783
+ return isErrorCode || isErrorStatus || isErrorSuccess;
2784
+ }
2107
2785
  extractBackendErrorResponse(error) {
2108
2786
  var _a, _b;
2109
2787
  const candidates = [
@@ -2515,6 +3193,101 @@ var Server = class {
2515
3193
  totalNotifyDurationMs: notifyEndAt - notifyStartAt
2516
3194
  });
2517
3195
  }
3196
+ /**
3197
+ * 订单变更后通知 sales 搜索订阅者。
3198
+ * 仅回传当前查询已返回订单号集合中的变更订单。
3199
+ *
3200
+ * @example
3201
+ * this.notifySalesSearchSubscribers({ list: [], changedOrders: [order], source: 'pubsub.bodyUpsert' })
3202
+ */
3203
+ notifySalesSearchSubscribers(payload) {
3204
+ if (this.salesSearchSubscribers.size === 0)
3205
+ return;
3206
+ const changedOrders = this.extractChangedOrdersFromPayload(payload);
3207
+ if (changedOrders.length === 0) {
3208
+ return;
3209
+ }
3210
+ for (const [subscriberId, subscriber] of this.salesSearchSubscribers.entries()) {
3211
+ try {
3212
+ const changedVisibleOrders = changedOrders.filter((order) => {
3213
+ const orderId = this.getSalesSearchOrderId(order);
3214
+ return !!orderId && subscriber.visibleOrderIds.has(orderId);
3215
+ });
3216
+ if (changedVisibleOrders.length === 0) {
3217
+ continue;
3218
+ }
3219
+ subscriber.callback(
3220
+ this.buildSalesSearchDeltaResponse(subscriber, changedVisibleOrders)
3221
+ );
3222
+ this.logInfo("notifySalesSearchSubscribers: 已推送 delta", {
3223
+ subscriberId,
3224
+ kind: subscriber.kind,
3225
+ count: changedVisibleOrders.length
3226
+ });
3227
+ } catch (error) {
3228
+ const errorMessage = error instanceof Error ? error.message : String(error);
3229
+ this.logError("notifySalesSearchSubscribers: 推送失败", {
3230
+ subscriberId,
3231
+ error: errorMessage
3232
+ });
3233
+ }
3234
+ }
3235
+ }
3236
+ /**
3237
+ * 从订单变更事件中提取明确 delta。
3238
+ *
3239
+ * @example
3240
+ * const list = this.extractChangedOrdersFromPayload(payload)
3241
+ */
3242
+ extractChangedOrdersFromPayload(payload) {
3243
+ if (!payload || Array.isArray(payload))
3244
+ return [];
3245
+ return Array.isArray(payload.changedOrders) ? payload.changedOrders : [];
3246
+ }
3247
+ /**
3248
+ * 构建与当前搜索接口一致的 delta 响应。
3249
+ *
3250
+ * @example
3251
+ * const response = this.buildSalesSearchDeltaResponse(subscriber, [order])
3252
+ */
3253
+ buildSalesSearchDeltaResponse(subscriber, changedOrders) {
3254
+ if (subscriber.kind === "aggregate") {
3255
+ return this.buildAggregateSalesSearchDeltaResponse(subscriber, changedOrders);
3256
+ }
3257
+ const data = subscriber.lastResponseData || {};
3258
+ return {
3259
+ code: 200,
3260
+ status: true,
3261
+ message: "",
3262
+ data: {
3263
+ ...data,
3264
+ list: changedOrders
3265
+ }
3266
+ };
3267
+ }
3268
+ /**
3269
+ * 构建聚合搜索接口的 sales 分组 delta 响应。
3270
+ *
3271
+ * @example
3272
+ * const response = this.buildAggregateSalesSearchDeltaResponse(subscriber, [order])
3273
+ */
3274
+ buildAggregateSalesSearchDeltaResponse(subscriber, changedOrders) {
3275
+ const data = subscriber.lastResponseData || {};
3276
+ const results = Array.isArray(data == null ? void 0 : data.results) ? data.results : [];
3277
+ const hasSalesGroup = results.some((item) => (item == null ? void 0 : item.module) === "sales");
3278
+ const nextResults = hasSalesGroup ? results.map(
3279
+ (item) => (item == null ? void 0 : item.module) === "sales" ? { ...item, list: changedOrders } : item
3280
+ ) : [{ module: "sales", list: changedOrders, count: changedOrders.length }];
3281
+ return {
3282
+ code: 200,
3283
+ status: true,
3284
+ message: "",
3285
+ data: {
3286
+ ...data,
3287
+ results: nextResults
3288
+ }
3289
+ };
3290
+ }
2518
3291
  /**
2519
3292
  * 预约数据变更后,遍历订阅者重新计算并通过 callback 推送
2520
3293
  */