@pisell/pisellos 2.3.29 → 2.3.30

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 (98) hide show
  1. package/dist/model/strategy/adapter/index.d.ts +0 -4
  2. package/dist/model/strategy/adapter/index.js +1 -5
  3. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  4. package/dist/modules/Discount/index.d.ts +2 -5
  5. package/dist/modules/Discount/index.js +7 -30
  6. package/dist/modules/Discount/types.d.ts +0 -4
  7. package/dist/modules/Order/index.d.ts +28 -10
  8. package/dist/modules/Order/index.js +747 -498
  9. package/dist/modules/Order/payment-utils.d.ts +23 -0
  10. package/dist/modules/Order/payment-utils.js +203 -0
  11. package/dist/modules/Order/types.d.ts +33 -3
  12. package/dist/modules/Order/utils.js +4 -4
  13. package/dist/modules/Payment/index.d.ts +2 -0
  14. package/dist/modules/Payment/index.js +78 -49
  15. package/dist/modules/Payment/types.d.ts +26 -24
  16. package/dist/modules/Payment/types.js +2 -0
  17. package/dist/modules/Product/index.d.ts +1 -1
  18. package/dist/modules/Product/types.d.ts +0 -22
  19. package/dist/modules/ProductList/index.d.ts +1 -1
  20. package/dist/modules/ProductList/index.js +2 -4
  21. package/dist/modules/ProductList/types.d.ts +0 -2
  22. package/dist/server/index.d.ts +14 -50
  23. package/dist/server/index.js +1975 -1395
  24. package/dist/server/modules/order/index.d.ts +40 -3
  25. package/dist/server/modules/order/index.js +1200 -501
  26. package/dist/server/modules/order/types.d.ts +11 -3
  27. package/dist/server/modules/order/types.js +1 -1
  28. package/dist/server/modules/products/index.d.ts +7 -26
  29. package/dist/server/modules/products/index.js +76 -167
  30. package/dist/server/modules/products/types.d.ts +0 -14
  31. package/dist/solution/BaseSales/index.d.ts +33 -5
  32. package/dist/solution/BaseSales/index.js +622 -345
  33. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +6 -1
  34. package/dist/solution/BookingByStep/index.d.ts +1 -1
  35. package/dist/solution/BookingTicket/index.d.ts +1 -1
  36. package/dist/solution/BookingTicket/index.js +2 -1
  37. package/dist/solution/BookingTicket/types.d.ts +0 -2
  38. package/dist/solution/ShopDiscount/index.js +14 -15
  39. package/dist/utils/payment-number.d.ts +9 -0
  40. package/dist/utils/payment-number.js +69 -0
  41. package/lib/model/strategy/adapter/index.d.ts +0 -4
  42. package/lib/model/strategy/adapter/index.js +2 -13
  43. package/lib/modules/Discount/index.d.ts +2 -5
  44. package/lib/modules/Discount/index.js +3 -23
  45. package/lib/modules/Discount/types.d.ts +0 -4
  46. package/lib/modules/Order/index.d.ts +28 -10
  47. package/lib/modules/Order/index.js +181 -73
  48. package/lib/modules/Order/payment-utils.d.ts +23 -0
  49. package/lib/modules/Order/payment-utils.js +193 -0
  50. package/lib/modules/Order/types.d.ts +33 -3
  51. package/lib/modules/Order/utils.js +2 -3
  52. package/lib/modules/Payment/index.d.ts +2 -0
  53. package/lib/modules/Payment/index.js +33 -12
  54. package/lib/modules/Payment/types.d.ts +26 -24
  55. package/lib/modules/Product/index.d.ts +1 -1
  56. package/lib/modules/Product/types.d.ts +0 -22
  57. package/lib/modules/ProductList/index.d.ts +1 -1
  58. package/lib/modules/ProductList/index.js +2 -4
  59. package/lib/modules/ProductList/types.d.ts +0 -2
  60. package/lib/server/index.d.ts +14 -50
  61. package/lib/server/index.js +633 -214
  62. package/lib/server/modules/order/index.d.ts +40 -3
  63. package/lib/server/modules/order/index.js +434 -31
  64. package/lib/server/modules/order/types.d.ts +11 -3
  65. package/lib/server/modules/products/index.d.ts +7 -26
  66. package/lib/server/modules/products/index.js +35 -114
  67. package/lib/server/modules/products/types.d.ts +0 -14
  68. package/lib/solution/BaseSales/index.d.ts +33 -5
  69. package/lib/solution/BaseSales/index.js +170 -19
  70. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +6 -1
  71. package/lib/solution/BookingByStep/index.d.ts +1 -1
  72. package/lib/solution/BookingTicket/index.d.ts +1 -1
  73. package/lib/solution/BookingTicket/index.js +2 -1
  74. package/lib/solution/BookingTicket/types.d.ts +0 -2
  75. package/lib/solution/ShopDiscount/index.js +1 -2
  76. package/lib/utils/payment-number.d.ts +9 -0
  77. package/lib/utils/payment-number.js +64 -0
  78. package/package.json +1 -1
  79. package/dist/model/strategy/adapter/dataVariant/adapter.d.ts +0 -50
  80. package/dist/model/strategy/adapter/dataVariant/adapter.js +0 -167
  81. package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +0 -89
  82. package/dist/model/strategy/adapter/dataVariant/evaluator.js +0 -780
  83. package/dist/model/strategy/adapter/dataVariant/examples.d.ts +0 -39
  84. package/dist/model/strategy/adapter/dataVariant/examples.js +0 -277
  85. package/dist/model/strategy/adapter/dataVariant/index.d.ts +0 -4
  86. package/dist/model/strategy/adapter/dataVariant/index.js +0 -4
  87. package/dist/model/strategy/adapter/dataVariant/type.d.ts +0 -148
  88. package/dist/model/strategy/adapter/dataVariant/type.js +0 -54
  89. package/lib/model/strategy/adapter/dataVariant/adapter.d.ts +0 -50
  90. package/lib/model/strategy/adapter/dataVariant/adapter.js +0 -149
  91. package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +0 -89
  92. package/lib/model/strategy/adapter/dataVariant/evaluator.js +0 -583
  93. package/lib/model/strategy/adapter/dataVariant/examples.d.ts +0 -39
  94. package/lib/model/strategy/adapter/dataVariant/examples.js +0 -293
  95. package/lib/model/strategy/adapter/dataVariant/index.d.ts +0 -4
  96. package/lib/model/strategy/adapter/dataVariant/index.js +0 -38
  97. package/lib/model/strategy/adapter/dataVariant/type.d.ts +0 -148
  98. package/lib/model/strategy/adapter/dataVariant/type.js +0 -31
@@ -34,6 +34,7 @@ __export(server_exports, {
34
34
  });
35
35
  module.exports = __toCommonJS(server_exports);
36
36
  var import_dayjs = __toESM(require("dayjs"));
37
+ var import_decimal = __toESM(require("decimal.js"));
37
38
  var import_products = require("./modules/products");
38
39
  var import_menu = require("./modules/menu");
39
40
  var import_quotation = require("./modules/quotation");
@@ -50,6 +51,7 @@ var import_types3 = require("./modules/order/types");
50
51
  var import_filterOrders = require("./modules/order/utils/filterOrders");
51
52
  var import_filterBookings = require("./modules/order/utils/filterBookings");
52
53
  var import_small_ticket = require("./utils/small-ticket");
54
+ var import_BaseSales = require("../solution/BaseSales");
53
55
  __reExport(server_exports, require("./modules"), module.exports);
54
56
  var PRODUCT_TITLE_SNAPSHOT_KEYS = [
55
57
  "en",
@@ -76,8 +78,6 @@ var Server = class {
76
78
  };
77
79
  // ---- 商品查询订阅者 ----
78
80
  this.productQuerySubscribers = /* @__PURE__ */ new Map();
79
- /** subscriberId → 智能定价变价时间点定时器句柄(与 subscriber 分离存储,便于 clear) */
80
- this.productQueryScheduleTimers = /* @__PURE__ */ new Map();
81
81
  // ---- 订单 / 预约列表查询订阅者 ----
82
82
  this.orderQuerySubscribers = /* @__PURE__ */ new Map();
83
83
  this.bookingQuerySubscribers = /* @__PURE__ */ new Map();
@@ -87,6 +87,7 @@ var Server = class {
87
87
  this.BOOKING_REMOTE_CACHE_MAX_ENTRIES = 80;
88
88
  this.salesSearchSubscribers = /* @__PURE__ */ new Map();
89
89
  this.deviceTaskActionsRegistered = false;
90
+ this.localPaymentUpdateQueues = /* @__PURE__ */ new Map();
90
91
  this.floorPlanQuerySubscribers = /* @__PURE__ */ new Map();
91
92
  // 模块注册表 - 定义所有可用的模块配置
92
93
  this.moduleRegistry = {
@@ -210,7 +211,7 @@ var Server = class {
210
211
  */
211
212
  this.handleProductQuery = async ({ url, method, data, config }) => {
212
213
  console.log("[Server] handleProductQuery:", url, method, data, config);
213
- const { menu_list_ids, schedule_datetime, schedule_date, customer_id, ids, extension_type, strategy_context } = data;
214
+ const { menu_list_ids, schedule_datetime, schedule_date, customer_id, ids, extension_type } = data;
214
215
  const { callback, subscriberId } = config || {};
215
216
  this.logInfo("handleProductQuery: 开始处理商品查询请求", {
216
217
  menu_list_ids,
@@ -218,32 +219,19 @@ var Server = class {
218
219
  schedule_datetime,
219
220
  schedule_date,
220
221
  customer_id,
221
- extension_type,
222
- strategyContextKeys: strategy_context ? Object.keys(strategy_context) : []
222
+ extension_type
223
223
  });
224
224
  if (subscriberId && typeof callback === "function") {
225
225
  this.productQuerySubscribers.set(subscriberId, {
226
226
  callback,
227
- context: { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type, strategy_context }
227
+ context: { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type }
228
228
  });
229
229
  this.logInfo("handleProductQuery: 已注册订阅者", {
230
230
  subscriberId,
231
231
  totalSubscribers: this.productQuerySubscribers.size
232
232
  });
233
233
  }
234
- const result = await this.computeProductQueryResult({
235
- menu_list_ids,
236
- ids,
237
- schedule_date,
238
- schedule_datetime,
239
- customer_id,
240
- extension_type,
241
- strategy_context
242
- });
243
- if (subscriberId && typeof callback === "function") {
244
- this.syncProductQueryScheduleTimers(subscriberId, strategy_context);
245
- }
246
- return result;
234
+ return this.computeProductQueryResult({ menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type });
247
235
  };
248
236
  /**
249
237
  * 按商品 id 查询单条(GET /shop/product/query/:productId)
@@ -575,6 +563,128 @@ var Server = class {
575
563
  title: "handleOrderSalesCheckout"
576
564
  });
577
565
  };
566
+ this.handleOrderSalesDraft = async ({ data }) => {
567
+ return this.handleOrderDraftSubmit({
568
+ data,
569
+ title: "handleOrderSalesDraft"
570
+ });
571
+ };
572
+ this.handleGetLocalPayment = async ({ data }) => {
573
+ const saleId = data == null ? void 0 : data.sale_id;
574
+ const paymentNumber = data == null ? void 0 : data.payment_number;
575
+ const operationId = this.createLocalPaymentOperationId("get");
576
+ const requestContext = {
577
+ operation_id: operationId,
578
+ sale_id: saleId ?? null,
579
+ payment_number: paymentNumber ?? null
580
+ };
581
+ this.logInfo("handleGetLocalPayment: 请求进入", requestContext);
582
+ if (saleId === void 0 || saleId === null || saleId === "" || paymentNumber === void 0 || paymentNumber === null || paymentNumber === "") {
583
+ this.logWarning("handleGetLocalPayment: 参数校验失败", {
584
+ ...requestContext,
585
+ missing_fields: [
586
+ ...saleId === void 0 || saleId === null || saleId === "" ? ["sale_id"] : [],
587
+ ...paymentNumber === void 0 || paymentNumber === null || paymentNumber === "" ? ["payment_number"] : []
588
+ ]
589
+ });
590
+ return {
591
+ code: 400,
592
+ status: false,
593
+ message: "sale_id 和 payment_number 必填",
594
+ data: null
595
+ };
596
+ }
597
+ if (!this.order) {
598
+ this.logError("handleGetLocalPayment: Order 模块未注册", requestContext);
599
+ return { code: 500, status: false, message: "Order 模块未注册", data: null };
600
+ }
601
+ const startedAt = Date.now();
602
+ try {
603
+ this.logInfo("handleGetLocalPayment: 开始查询本地支付项", requestContext);
604
+ const found = await this.order.getLocalPayment({
605
+ saleId,
606
+ paymentNumber,
607
+ operationId
608
+ });
609
+ if (!found) {
610
+ this.logWarning("handleGetLocalPayment: 本地支付项不存在", {
611
+ ...requestContext,
612
+ duration_ms: Date.now() - startedAt
613
+ });
614
+ return { code: 404, status: false, message: "本地支付项不存在", data: null };
615
+ }
616
+ this.logInfo("handleGetLocalPayment: 查询命中", {
617
+ ...requestContext,
618
+ duration_ms: Date.now() - startedAt,
619
+ matched_by: found.matchedBy,
620
+ payment_index: found.paymentIndex,
621
+ ...this.buildLocalPaymentOrderLogContext(found.order),
622
+ payment: found.payment
623
+ });
624
+ return { code: 200, status: true, message: "", data: found.payment };
625
+ } catch (error) {
626
+ this.logError("handleGetLocalPayment: 查询异常", {
627
+ ...requestContext,
628
+ duration_ms: Date.now() - startedAt,
629
+ error: error instanceof Error ? error.message : String(error),
630
+ error_detail: this.normalizeUnknownError(error)
631
+ });
632
+ throw error;
633
+ }
634
+ };
635
+ this.handleUpdateLocalPayment = async ({ data }) => {
636
+ const saleId = data == null ? void 0 : data.sale_id;
637
+ const paymentNumber = data == null ? void 0 : data.payment_number;
638
+ const number = data == null ? void 0 : data.number;
639
+ const status = data == null ? void 0 : data.status;
640
+ const serviceCharge = data == null ? void 0 : data.service_charge;
641
+ const cardReaderSurcharge = data == null ? void 0 : data.card_reader_surcharge;
642
+ const hasSurchargeInput = serviceCharge !== void 0 || cardReaderSurcharge !== void 0;
643
+ const invalidSurchargeFields = this.getInvalidLocalPaymentSurchargeFields(
644
+ serviceCharge,
645
+ cardReaderSurcharge
646
+ );
647
+ const operationId = this.createLocalPaymentOperationId("update");
648
+ const requestContext = {
649
+ operation_id: operationId,
650
+ sale_id: saleId ?? null,
651
+ payment_number: paymentNumber ?? null,
652
+ transaction_number: number ?? null,
653
+ requested_status: status ?? null,
654
+ service_charge: serviceCharge ?? null,
655
+ card_reader_surcharge: cardReaderSurcharge ?? null
656
+ };
657
+ this.logInfo("handleUpdateLocalPayment: 请求进入", requestContext);
658
+ if (saleId === void 0 || saleId === null || saleId === "" || paymentNumber === void 0 || paymentNumber === null || paymentNumber === "" || number === void 0 || number === null || number === "" || status !== "success" && status !== "fail" || invalidSurchargeFields.length > 0) {
659
+ this.logWarning("handleUpdateLocalPayment: 参数校验失败", {
660
+ ...requestContext,
661
+ missing_or_invalid_fields: [
662
+ ...saleId === void 0 || saleId === null || saleId === "" ? ["sale_id"] : [],
663
+ ...paymentNumber === void 0 || paymentNumber === null || paymentNumber === "" ? ["payment_number"] : [],
664
+ ...number === void 0 || number === null || number === "" ? ["number"] : [],
665
+ ...status !== "success" && status !== "fail" ? ["status"] : [],
666
+ ...invalidSurchargeFields
667
+ ]
668
+ });
669
+ return {
670
+ code: 400,
671
+ status: false,
672
+ message: invalidSurchargeFields.length > 0 ? `手续费参数非法: ${invalidSurchargeFields.join(", ")}` : "sale_id、payment_number、number 必填,status 仅支持 success/fail",
673
+ data: null
674
+ };
675
+ }
676
+ const queueKey = `${String(saleId)}:${String(paymentNumber)}`;
677
+ return this.runLocalPaymentUpdateInQueue(queueKey, () => this.processLocalPaymentUpdate({
678
+ operationId,
679
+ saleId,
680
+ paymentNumber,
681
+ number: String(number),
682
+ status,
683
+ serviceCharge,
684
+ cardReaderSurcharge,
685
+ hasSurchargeInput
686
+ }), requestContext);
687
+ };
578
688
  this.handleOrderCheckout = async ({ data }) => {
579
689
  return this.handleOrderCheckoutSubmit({
580
690
  backendPath: "/order/checkout",
@@ -1439,13 +1549,15 @@ var Server = class {
1439
1549
  ...checkoutData,
1440
1550
  ...fresh,
1441
1551
  external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
1442
- need_sync: 0
1552
+ need_sync: 0,
1553
+ is_draft_order: 0
1443
1554
  } : {
1444
1555
  ...fresh,
1445
1556
  external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
1446
- need_sync: 0
1557
+ need_sync: 0,
1558
+ is_draft_order: 0
1447
1559
  };
1448
- await this.order.upsertOrdersFromRemote([syncedOrder]);
1560
+ await this.order.upsertOrdersFromRemote([syncedOrder], "checkoutSync");
1449
1561
  this.logInfo(`${title}: sync_sales 完整订单已同步到本地`, {
1450
1562
  order_id: fresh.order_id,
1451
1563
  external_sale_number: syncedOrder.external_sale_number,
@@ -1463,7 +1575,8 @@ var Server = class {
1463
1575
  ...checkoutData,
1464
1576
  ...patch,
1465
1577
  external_sale_number: externalSaleNumber,
1466
- need_sync: 0
1578
+ need_sync: 0,
1579
+ is_draft_order: 0
1467
1580
  };
1468
1581
  this.logInfo(`${title}: sync_sales 已按 external_sale_number 标记本地订单`, {
1469
1582
  order_id: (syncedOrder == null ? void 0 : syncedOrder.order_id) ?? null,
@@ -1843,6 +1956,11 @@ var Server = class {
1843
1956
  path: "/shop/order/sales/checkout",
1844
1957
  handler: this.handleOrderSalesCheckout.bind(this)
1845
1958
  },
1959
+ {
1960
+ method: "post",
1961
+ path: "/shop/order/sales/draft",
1962
+ handler: this.handleOrderSalesDraft.bind(this)
1963
+ },
1846
1964
  {
1847
1965
  method: "post",
1848
1966
  path: "/order/checkout",
@@ -1853,6 +1971,16 @@ var Server = class {
1853
1971
  path: "/shop/local/print-order",
1854
1972
  handler: this.handleLocalPrintOrder.bind(this)
1855
1973
  },
1974
+ {
1975
+ method: "post",
1976
+ path: "/shop/local/getLocalPayment",
1977
+ handler: this.handleGetLocalPayment.bind(this)
1978
+ },
1979
+ {
1980
+ method: "post",
1981
+ path: "/shop/local/updateLocalPayment",
1982
+ handler: this.handleUpdateLocalPayment.bind(this)
1983
+ },
1856
1984
  {
1857
1985
  method: "post",
1858
1986
  path: "/shop/machinecode/batch",
@@ -1926,7 +2054,6 @@ var Server = class {
1926
2054
  */
1927
2055
  removeProductQuerySubscriber(subscriberId) {
1928
2056
  if (subscriberId) {
1929
- this.clearSubscriberScheduleTimers(subscriberId);
1930
2057
  this.productQuerySubscribers.delete(subscriberId);
1931
2058
  this.logInfo("removeProductQuerySubscriber: 已移除订阅者", {
1932
2059
  subscriberId,
@@ -1934,156 +2061,6 @@ var Server = class {
1934
2061
  });
1935
2062
  }
1936
2063
  }
1937
- /**
1938
- * 构建商品 query 响应 data 段,附带智能定价 schedule_time_points 元数据。
1939
- */
1940
- buildProductQueryResultPayload(list, count) {
1941
- var _a, _b;
1942
- return {
1943
- list,
1944
- count: count ?? list.length,
1945
- schedule_time_points: ((_b = (_a = this.products) == null ? void 0 : _a.getLastScheduleTimePoints) == null ? void 0 : _b.call(_a)) ?? []
1946
- };
1947
- }
1948
- /**
1949
- * 是否启用商品 query 订阅的 schedule 时间点定时重算。
1950
- * strategy_context.enable_schedule_reload === false 时关闭。
1951
- */
1952
- shouldScheduleProductQueryReload(strategy_context) {
1953
- return (strategy_context == null ? void 0 : strategy_context.enable_schedule_reload) !== false;
1954
- }
1955
- /**
1956
- * 清除指定 subscriber 的全部 schedule 定时器,防止重复 query 或 unsubscribe 后泄漏。
1957
- */
1958
- clearSubscriberScheduleTimers(subscriberId) {
1959
- const timers = this.productQueryScheduleTimers.get(subscriberId);
1960
- if (timers == null ? void 0 : timers.length) {
1961
- timers.forEach((timerId) => clearTimeout(timerId));
1962
- }
1963
- this.productQueryScheduleTimers.delete(subscriberId);
1964
- const subscriber = this.productQuerySubscribers.get(subscriberId);
1965
- if (subscriber) {
1966
- subscriber.scheduleTimerIds = [];
1967
- }
1968
- }
1969
- /**
1970
- * 从 productQueryScheduleTimers 移除已触发的 timer 引用。
1971
- */
1972
- removeScheduleTimerRef(subscriberId, timerId) {
1973
- const timers = this.productQueryScheduleTimers.get(subscriberId);
1974
- if (!(timers == null ? void 0 : timers.length))
1975
- return;
1976
- const next = timers.filter((id) => id !== timerId);
1977
- if (next.length === 0) {
1978
- this.productQueryScheduleTimers.delete(subscriberId);
1979
- } else {
1980
- this.productQueryScheduleTimers.set(subscriberId, next);
1981
- }
1982
- const subscriber = this.productQuerySubscribers.get(subscriberId);
1983
- if (subscriber) {
1984
- subscriber.scheduleTimerIds = next;
1985
- }
1986
- }
1987
- /**
1988
- * 计算 schedule 变价时间点到当前时刻的延迟(ms)。已过期返回 -1。
1989
- */
1990
- computeScheduleTimePointDelayMs(scheduleDate, timePoint) {
1991
- const parts = timePoint.split(":");
1992
- if (parts.length < 2)
1993
- return -1;
1994
- const hours = parseInt(parts[0], 10);
1995
- const minutes = parseInt(parts[1], 10);
1996
- if (!Number.isFinite(hours) || !Number.isFinite(minutes))
1997
- return -1;
1998
- const target = (0, import_dayjs.default)(scheduleDate).hour(hours).minute(minutes).second(4).millisecond(0);
1999
- const delayMs = target.diff((0, import_dayjs.default)());
2000
- return delayMs >= 0 ? delayMs : -1;
2001
- }
2002
- /**
2003
- * 定时重算前刷新 subscriber schedule 上下文:使用执行瞬间时间,禁止沿用首次 query 的 schedule_datetime。
2004
- */
2005
- refreshSubscriberScheduleAtExecution(subscriber) {
2006
- const executedAt = (0, import_dayjs.default)();
2007
- const bookingDate = subscriber.context.schedule_date || executedAt.format("YYYY-MM-DD");
2008
- subscriber.context.schedule_date = bookingDate;
2009
- subscriber.context.schedule_datetime = `${bookingDate} ${executedAt.format("HH:mm:ss")}`;
2010
- }
2011
- /**
2012
- * 为 subscriber 注册智能定价 scheduleTimePoints 定时重算。
2013
- * 必须先 clearSubscriberScheduleTimers,再调用本方法。
2014
- */
2015
- scheduleSubscriberTimePointReloads(subscriberId, timePoints) {
2016
- const subscriber = this.productQuerySubscribers.get(subscriberId);
2017
- if (!subscriber || !timePoints.length)
2018
- return;
2019
- const scheduleDate = subscriber.context.schedule_date || (0, import_dayjs.default)().format("YYYY-MM-DD");
2020
- const timerIds = [];
2021
- for (const timePoint of timePoints) {
2022
- const delayMs = this.computeScheduleTimePointDelayMs(scheduleDate, timePoint);
2023
- if (delayMs < 0)
2024
- continue;
2025
- const timerId = setTimeout(() => {
2026
- void this.onScheduleTimePointTimerFire(subscriberId, timerId);
2027
- }, delayMs);
2028
- timerIds.push(timerId);
2029
- }
2030
- if (timerIds.length > 0) {
2031
- this.productQueryScheduleTimers.set(subscriberId, timerIds);
2032
- subscriber.scheduleTimerIds = timerIds;
2033
- this.logInfo("scheduleSubscriberTimePointReloads: 已注册定时器", {
2034
- subscriberId,
2035
- timerCount: timerIds.length,
2036
- timePoints
2037
- });
2038
- }
2039
- }
2040
- /**
2041
- * schedule 变价时间点定时器触发:刷新 schedule_datetime 后重算并 callback。
2042
- */
2043
- async onScheduleTimePointTimerFire(subscriberId, timerId) {
2044
- this.removeScheduleTimerRef(subscriberId, timerId);
2045
- if (!this.productQuerySubscribers.has(subscriberId))
2046
- return;
2047
- const subscriber = this.productQuerySubscribers.get(subscriberId);
2048
- this.refreshSubscriberScheduleAtExecution(subscriber);
2049
- await this.recomputeAndNotifySubscriber(subscriberId);
2050
- }
2051
- /**
2052
- * 对单个商品 query 订阅者重算并推送(定时路径;不新建 schedule timer)。
2053
- */
2054
- async recomputeAndNotifySubscriber(subscriberId) {
2055
- const subscriber = this.productQuerySubscribers.get(subscriberId);
2056
- if (!subscriber)
2057
- return;
2058
- try {
2059
- const result = await this.computeProductQueryResult(subscriber.context);
2060
- subscriber.callback(result);
2061
- this.logInfo("recomputeAndNotifySubscriber: 已推送", {
2062
- subscriberId,
2063
- schedule_datetime: subscriber.context.schedule_datetime
2064
- });
2065
- } catch (error) {
2066
- const errorMessage = error instanceof Error ? error.message : String(error);
2067
- this.logError("recomputeAndNotifySubscriber: 推送失败", {
2068
- subscriberId,
2069
- error: errorMessage
2070
- });
2071
- }
2072
- }
2073
- /**
2074
- * query 完成后为 subscriber 同步 schedule 定时器(先 clear 再 schedule)。
2075
- */
2076
- syncProductQueryScheduleTimers(subscriberId, strategy_context) {
2077
- var _a, _b;
2078
- this.clearSubscriberScheduleTimers(subscriberId);
2079
- if (!this.shouldScheduleProductQueryReload(strategy_context)) {
2080
- return;
2081
- }
2082
- const timePoints = ((_b = (_a = this.products) == null ? void 0 : _a.getLastScheduleTimePoints) == null ? void 0 : _b.call(_a)) ?? [];
2083
- if (timePoints.length > 0) {
2084
- this.scheduleSubscriberTimePointReloads(subscriberId, timePoints);
2085
- }
2086
- }
2087
2064
  /**
2088
2065
  * 执行 sales 搜索并登记可见订单号。
2089
2066
  * 搜索参数完全透传后端,OS 不做过滤、筛选、排序。
@@ -2694,6 +2671,403 @@ var Server = class {
2694
2671
  };
2695
2672
  }
2696
2673
  }
2674
+ createLocalPaymentOperationId(action) {
2675
+ return `local_payment_${action}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
2676
+ }
2677
+ buildLocalPaymentOrderLogContext(order) {
2678
+ if (!order)
2679
+ return {};
2680
+ return {
2681
+ order_id: order.order_id ?? null,
2682
+ external_sale_number: order.external_sale_number ?? null,
2683
+ order_number: order.order_number ?? null,
2684
+ shop_order_number: order.shop_order_number ?? null,
2685
+ shop_full_order_number: order.shop_full_order_number ?? null,
2686
+ order_status: order.status ?? null,
2687
+ payment_status: order.payment_status ?? null,
2688
+ is_draft_order: Number(order.is_draft_order || 0),
2689
+ need_sync: Number(order.need_sync || 0),
2690
+ platform: order.platform ?? null,
2691
+ business_code: order.business_code ?? null,
2692
+ order_sales_channel: order.order_sales_channel ?? null,
2693
+ sales_channel: order.sales_channel ?? null,
2694
+ order_type: order.type ?? null,
2695
+ payments_count: Array.isArray(order.payments) ? order.payments.length : 0
2696
+ };
2697
+ }
2698
+ isValidLocalPaymentDecimal(value) {
2699
+ if (typeof value !== "string" && typeof value !== "number")
2700
+ return false;
2701
+ if (typeof value === "string" && value.trim() === "")
2702
+ return false;
2703
+ try {
2704
+ return new import_decimal.default(value).isFinite();
2705
+ } catch {
2706
+ return false;
2707
+ }
2708
+ }
2709
+ getInvalidLocalPaymentSurchargeFields(serviceCharge, cardReaderSurcharge) {
2710
+ const invalidFields = [];
2711
+ if (serviceCharge !== void 0) {
2712
+ if (serviceCharge === null || typeof serviceCharge !== "object" || Array.isArray(serviceCharge)) {
2713
+ invalidFields.push("service_charge");
2714
+ } else {
2715
+ const input = serviceCharge;
2716
+ if (input.fixed !== void 0 && !this.isValidLocalPaymentDecimal(input.fixed)) {
2717
+ invalidFields.push("service_charge.fixed");
2718
+ }
2719
+ if (input.percentage !== void 0 && !this.isValidLocalPaymentDecimal(input.percentage)) {
2720
+ invalidFields.push("service_charge.percentage");
2721
+ }
2722
+ }
2723
+ }
2724
+ if (cardReaderSurcharge !== void 0 && !this.isValidLocalPaymentDecimal(cardReaderSurcharge)) {
2725
+ invalidFields.push("card_reader_surcharge");
2726
+ }
2727
+ return invalidFields;
2728
+ }
2729
+ buildLocalPaymentSurchargeUpdate(params) {
2730
+ var _a, _b, _c;
2731
+ const amount = new import_decimal.default(((_a = params.serviceCharge) == null ? void 0 : _a.fixed) || 0).plus(params.cardReaderSurcharge || 0).toFixed(2);
2732
+ const serviceFee = new import_decimal.default(params.paymentAmount || 0).times(((_b = params.serviceCharge) == null ? void 0 : _b.percentage) || 0).plus(amount).toDecimalPlaces(2).toFixed(2);
2733
+ return {
2734
+ service_charge: {
2735
+ amount,
2736
+ ...((_c = params.serviceCharge) == null ? void 0 : _c.percentage) !== void 0 ? { percentage: params.serviceCharge.percentage } : {}
2737
+ },
2738
+ service_fee: serviceFee
2739
+ };
2740
+ }
2741
+ async runLocalPaymentUpdateInQueue(key, task, context) {
2742
+ var _a;
2743
+ const queuedAt = Date.now();
2744
+ const hasPreviousTask = this.localPaymentUpdateQueues.has(key);
2745
+ const previous = this.localPaymentUpdateQueues.get(key) || Promise.resolve();
2746
+ this.logInfo("handleUpdateLocalPayment: 串行队列入队", {
2747
+ ...context,
2748
+ queue_key: key,
2749
+ waiting_for_previous: hasPreviousTask,
2750
+ active_queue_count: this.localPaymentUpdateQueues.size
2751
+ });
2752
+ const current = previous.catch(() => void 0).then(async () => {
2753
+ this.logInfo("handleUpdateLocalPayment: 串行队列开始执行", {
2754
+ ...context,
2755
+ queue_key: key,
2756
+ queue_wait_ms: Date.now() - queuedAt
2757
+ });
2758
+ return task();
2759
+ });
2760
+ const tail = current.then(() => void 0, () => void 0);
2761
+ this.localPaymentUpdateQueues.set(key, tail);
2762
+ try {
2763
+ const result = await current;
2764
+ this.logInfo("handleUpdateLocalPayment: 串行队列执行完成", {
2765
+ ...context,
2766
+ queue_key: key,
2767
+ total_duration_ms: Date.now() - queuedAt,
2768
+ result_code: result == null ? void 0 : result.code,
2769
+ result_status: result == null ? void 0 : result.status,
2770
+ payment: (_a = result == null ? void 0 : result.data) == null ? void 0 : _a.payment
2771
+ });
2772
+ return result;
2773
+ } catch (error) {
2774
+ this.logError("handleUpdateLocalPayment: 串行队列执行失败", {
2775
+ ...context,
2776
+ queue_key: key,
2777
+ total_duration_ms: Date.now() - queuedAt,
2778
+ error: error instanceof Error ? error.message : String(error),
2779
+ error_detail: this.normalizeUnknownError(error)
2780
+ });
2781
+ throw error;
2782
+ } finally {
2783
+ let released = false;
2784
+ if (this.localPaymentUpdateQueues.get(key) === tail) {
2785
+ this.localPaymentUpdateQueues.delete(key);
2786
+ released = true;
2787
+ }
2788
+ this.logInfo("handleUpdateLocalPayment: 串行队列释放", {
2789
+ ...context,
2790
+ queue_key: key,
2791
+ released,
2792
+ active_queue_count: this.localPaymentUpdateQueues.size
2793
+ });
2794
+ }
2795
+ }
2796
+ async processLocalPaymentUpdate(params) {
2797
+ var _a, _b, _c;
2798
+ const requestContext = {
2799
+ operation_id: params.operationId,
2800
+ sale_id: params.saleId,
2801
+ payment_number: params.paymentNumber,
2802
+ transaction_number: params.number,
2803
+ requested_status: params.status,
2804
+ service_charge: params.serviceCharge ?? null,
2805
+ card_reader_surcharge: params.cardReaderSurcharge ?? null
2806
+ };
2807
+ this.logInfo("processLocalPaymentUpdate: 开始处理", requestContext);
2808
+ if (!this.order) {
2809
+ this.logError("processLocalPaymentUpdate: Order 模块未注册", requestContext);
2810
+ return { code: 500, status: false, message: "Order 模块未注册", data: null };
2811
+ }
2812
+ this.logInfo("processLocalPaymentUpdate: 开始查询本地支付项", requestContext);
2813
+ const found = await this.order.getLocalPayment({
2814
+ saleId: params.saleId,
2815
+ paymentNumber: params.paymentNumber,
2816
+ operationId: params.operationId
2817
+ });
2818
+ if (!found) {
2819
+ this.logWarning("processLocalPaymentUpdate: 本地支付项不存在", requestContext);
2820
+ return { code: 404, status: false, message: "本地支付项不存在", data: null };
2821
+ }
2822
+ const surchargeUpdate = params.status === "success" && params.hasSurchargeInput ? this.buildLocalPaymentSurchargeUpdate({
2823
+ paymentAmount: (_a = found.payment) == null ? void 0 : _a.amount,
2824
+ serviceCharge: params.serviceCharge,
2825
+ cardReaderSurcharge: params.cardReaderSurcharge
2826
+ }) : void 0;
2827
+ const incomingPaymentUpdate = params.status === "success" ? {
2828
+ status: "paid",
2829
+ ...surchargeUpdate || {},
2830
+ metadata: {
2831
+ unique_payment_number: params.number,
2832
+ transactions: [{ number: params.number, status: "success" }]
2833
+ }
2834
+ } : {
2835
+ metadata: {
2836
+ transactions: [{ number: params.number, status: "fail" }]
2837
+ }
2838
+ };
2839
+ const transactions = Array.isArray((_c = (_b = found.payment) == null ? void 0 : _b.metadata) == null ? void 0 : _c.transactions) ? found.payment.metadata.transactions : [];
2840
+ const existingTransaction = transactions.find((item) => String((item == null ? void 0 : item.number) || "") === params.number);
2841
+ const hasRecordedSuccess = transactions.some((item) => (item == null ? void 0 : item.status) === "success");
2842
+ const orderIsDraft = Number(found.order.is_draft_order || 0) === 1;
2843
+ const foundContext = {
2844
+ ...requestContext,
2845
+ matched_by: found.matchedBy,
2846
+ payment_index: found.paymentIndex,
2847
+ ...this.buildLocalPaymentOrderLogContext(found.order),
2848
+ payment: found.payment,
2849
+ incoming_payment_update: incomingPaymentUpdate,
2850
+ existing_transaction: existingTransaction || null,
2851
+ has_recorded_success: hasRecordedSuccess
2852
+ };
2853
+ this.logInfo("processLocalPaymentUpdate: 查询命中", foundContext);
2854
+ if (params.status === "fail" && (found.payment.status === "paid" || hasRecordedSuccess)) {
2855
+ this.logInfo("processLocalPaymentUpdate: 幂等返回", {
2856
+ ...foundContext,
2857
+ idempotent_reason: "ignore_failure_after_success"
2858
+ });
2859
+ return {
2860
+ code: 200,
2861
+ status: true,
2862
+ message: "",
2863
+ data: { payment: found.payment, order: found.order, idempotent: true }
2864
+ };
2865
+ }
2866
+ const alreadyRecordedFailure = params.status === "fail" && (existingTransaction == null ? void 0 : existingTransaction.status) === "fail";
2867
+ if (alreadyRecordedFailure) {
2868
+ this.logInfo("processLocalPaymentUpdate: 幂等返回", {
2869
+ ...foundContext,
2870
+ idempotent_reason: "failure_already_recorded"
2871
+ });
2872
+ return {
2873
+ code: 200,
2874
+ status: true,
2875
+ message: "",
2876
+ data: { payment: found.payment, order: found.order, idempotent: true }
2877
+ };
2878
+ }
2879
+ if (params.status === "success" && (existingTransaction == null ? void 0 : existingTransaction.status) === "success" && found.payment.status === "paid" && !orderIsDraft) {
2880
+ this.logInfo("processLocalPaymentUpdate: 幂等返回", {
2881
+ ...foundContext,
2882
+ idempotent_reason: "success_already_committed"
2883
+ });
2884
+ return {
2885
+ code: 200,
2886
+ status: true,
2887
+ message: "",
2888
+ data: { payment: found.payment, order: found.order, idempotent: true }
2889
+ };
2890
+ }
2891
+ if (params.status === "success") {
2892
+ this.logInfo("processLocalPaymentUpdate: 进入 success 恢复分支", {
2893
+ ...foundContext,
2894
+ force_submit_if_paid: found.payment.status === "paid" && orderIsDraft
2895
+ });
2896
+ return this.processSuccessfulLocalPayment({
2897
+ ...params,
2898
+ order: found.order,
2899
+ payment: found.payment,
2900
+ matchBy: found.matchedBy === "payment_number" ? "payment_number" : "compat",
2901
+ forceSubmitIfPaid: found.payment.status === "paid" && orderIsDraft,
2902
+ paymentUpdate: incomingPaymentUpdate
2903
+ });
2904
+ }
2905
+ this.logInfo("processLocalPaymentUpdate: 进入 fail 本地更新分支", {
2906
+ ...foundContext,
2907
+ incoming_payment_update: incomingPaymentUpdate
2908
+ });
2909
+ let updated;
2910
+ try {
2911
+ updated = await this.order.updateLocalPayment({
2912
+ saleId: params.saleId,
2913
+ paymentNumber: params.paymentNumber,
2914
+ operationId: params.operationId,
2915
+ updates: incomingPaymentUpdate
2916
+ });
2917
+ } catch (error) {
2918
+ this.logError("processLocalPaymentUpdate: fail 本地更新失败", {
2919
+ ...foundContext,
2920
+ incoming_payment_update: incomingPaymentUpdate,
2921
+ error: error instanceof Error ? error.message : String(error),
2922
+ error_detail: this.normalizeUnknownError(error)
2923
+ });
2924
+ throw error;
2925
+ }
2926
+ if (!updated) {
2927
+ this.logWarning("processLocalPaymentUpdate: fail 本地更新未命中", foundContext);
2928
+ return { code: 404, status: false, message: "本地支付项不存在", data: null };
2929
+ }
2930
+ this.logInfo("processLocalPaymentUpdate: fail 本地更新完成", {
2931
+ ...requestContext,
2932
+ ...this.buildLocalPaymentOrderLogContext(updated.order),
2933
+ previous_payment: updated.previousPayment,
2934
+ payment: updated.payment
2935
+ });
2936
+ return {
2937
+ code: 200,
2938
+ status: true,
2939
+ message: "",
2940
+ data: {
2941
+ local_only: true,
2942
+ payment: updated.payment,
2943
+ order: updated.order
2944
+ }
2945
+ };
2946
+ }
2947
+ async processSuccessfulLocalPayment(params) {
2948
+ var _a, _b, _c, _d, _e;
2949
+ const moduleName = `local_payment_recovery_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
2950
+ const baseSales = new import_BaseSales.BaseSalesImpl(moduleName);
2951
+ const startedAt = Date.now();
2952
+ const recoveryContext = {
2953
+ operation_id: params.operationId,
2954
+ sale_id: params.saleId,
2955
+ payment_number: params.paymentNumber,
2956
+ transaction_number: params.number,
2957
+ requested_status: "success",
2958
+ match_by: params.matchBy,
2959
+ force_submit_if_paid: params.forceSubmitIfPaid,
2960
+ incoming_payment_update: params.paymentUpdate,
2961
+ base_sales_module_name: moduleName,
2962
+ ...this.buildLocalPaymentOrderLogContext(params.order),
2963
+ payment: params.payment
2964
+ };
2965
+ this.logInfo("processSuccessfulLocalPayment: 创建临时 BaseSales", recoveryContext);
2966
+ try {
2967
+ const order = this.sanitizeLocalRecoveryOrder(params.order);
2968
+ this.logInfo("processSuccessfulLocalPayment: 本地订单清洗完成", {
2969
+ ...recoveryContext,
2970
+ sanitized_order_id: order.order_id ?? null,
2971
+ removed_synthetic_order_id: params.order.order_id != null && order.order_id == null
2972
+ });
2973
+ await baseSales.initialize(this.core, {
2974
+ otherParams: {
2975
+ platform: order.platform,
2976
+ businessCode: order.business_code,
2977
+ business_code: order.business_code,
2978
+ channel: order.order_sales_channel || order.sales_channel,
2979
+ type: order.type,
2980
+ enableTempOrderPersist: false
2981
+ }
2982
+ });
2983
+ this.logInfo("processSuccessfulLocalPayment: BaseSales 初始化完成", recoveryContext);
2984
+ await baseSales.loadSalesDetail({
2985
+ externalSaleNumber: String(params.saleId),
2986
+ preloadedSalesDetail: order
2987
+ });
2988
+ this.logInfo("processSuccessfulLocalPayment: 本地订单 hydrate 完成", recoveryContext);
2989
+ this.logInfo("processSuccessfulLocalPayment: 开始更新支付项并提交", {
2990
+ ...recoveryContext,
2991
+ incoming_payment_update: params.paymentUpdate
2992
+ });
2993
+ const result = await baseSales.updateOrderPayment(
2994
+ params.paymentNumber,
2995
+ params.paymentUpdate,
2996
+ {
2997
+ submitWhenPaid: true,
2998
+ matchBy: params.matchBy,
2999
+ forceSubmitIfPaid: params.forceSubmitIfPaid,
3000
+ applyUpdatesWhenPaid: params.forceSubmitIfPaid,
3001
+ smallTicketDataFlag: 1
3002
+ }
3003
+ );
3004
+ this.logInfo("processSuccessfulLocalPayment: 支付恢复完成", {
3005
+ ...recoveryContext,
3006
+ duration_ms: Date.now() - startedAt,
3007
+ payment: result.payment,
3008
+ payments_count: ((_a = result.payments) == null ? void 0 : _a.length) || 0,
3009
+ summary: result.summary,
3010
+ sync_result: result.syncResult ? {
3011
+ is_fully_paid: result.syncResult.isFullyPaid,
3012
+ is_order_fully_paid: result.syncResult.isOrderFullyPaid,
3013
+ is_deposit_fully_paid: result.syncResult.isDepositFullyPaid,
3014
+ payment_stage: result.syncResult.paymentStage,
3015
+ deposit_amount: result.syncResult.depositAmount,
3016
+ order_expected_amount: result.syncResult.orderExpectedAmount,
3017
+ submit_result_code: (_b = result.syncResult.submitResult) == null ? void 0 : _b.code,
3018
+ submit_result_status: (_c = result.syncResult.submitResult) == null ? void 0 : _c.status
3019
+ } : null,
3020
+ draft_result: result.draftResult ? {
3021
+ code: (_d = result.draftResult) == null ? void 0 : _d.code,
3022
+ status: (_e = result.draftResult) == null ? void 0 : _e.status
3023
+ } : null,
3024
+ draft_error: result.draftError instanceof Error ? result.draftError.message : result.draftError
3025
+ });
3026
+ return {
3027
+ code: 200,
3028
+ status: true,
3029
+ message: "",
3030
+ data: {
3031
+ payment: result.payment,
3032
+ payments: result.payments,
3033
+ summary: result.summary,
3034
+ sync_result: result.syncResult
3035
+ }
3036
+ };
3037
+ } catch (error) {
3038
+ const message = error instanceof Error ? error.message : String(error);
3039
+ this.logError("processSuccessfulLocalPayment: 支付恢复失败", {
3040
+ ...recoveryContext,
3041
+ duration_ms: Date.now() - startedAt,
3042
+ error: message,
3043
+ error_detail: this.normalizeUnknownError(error)
3044
+ });
3045
+ return { code: 500, status: false, message, data: null };
3046
+ } finally {
3047
+ try {
3048
+ await baseSales.destroy();
3049
+ this.logInfo("processSuccessfulLocalPayment: 临时 BaseSales 销毁完成", {
3050
+ ...recoveryContext,
3051
+ duration_ms: Date.now() - startedAt
3052
+ });
3053
+ } catch (error) {
3054
+ this.logError("processSuccessfulLocalPayment: 临时 BaseSales 销毁失败", {
3055
+ ...recoveryContext,
3056
+ duration_ms: Date.now() - startedAt,
3057
+ error: error instanceof Error ? error.message : String(error),
3058
+ error_detail: this.normalizeUnknownError(error)
3059
+ });
3060
+ }
3061
+ }
3062
+ }
3063
+ sanitizeLocalRecoveryOrder(order) {
3064
+ const next = { ...order };
3065
+ const externalSaleNumber = next.external_sale_number;
3066
+ if (Number(next.is_draft_order || 0) === 1 && next.order_id !== void 0 && externalSaleNumber !== void 0 && String(next.order_id) === String(externalSaleNumber)) {
3067
+ delete next.order_id;
3068
+ }
3069
+ return next;
3070
+ }
2697
3071
  getDeviceTaskPlugin() {
2698
3072
  var _a, _b;
2699
3073
  return ((_b = (_a = this.app) == null ? void 0 : _a.getPlugin) == null ? void 0 : _b.call(_a, "deviceTask")) || null;
@@ -3214,6 +3588,59 @@ var Server = class {
3214
3588
  };
3215
3589
  }
3216
3590
  }
3591
+ async handleOrderDraftSubmit(params) {
3592
+ var _a, _b, _c;
3593
+ const { data, title } = params;
3594
+ this.logInfo(`${title}: 开始处理`, {
3595
+ order_id: data == null ? void 0 : data.order_id,
3596
+ external_sale_number: data == null ? void 0 : data.external_sale_number,
3597
+ order_number: data == null ? void 0 : data.order_number
3598
+ });
3599
+ const normalizedData = await this.normalizeCheckoutSubmitData(data, title);
3600
+ const createdAt = normalizedData.created_at || normalizedData.create_date || (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
3601
+ const draftOrder = {
3602
+ ...normalizedData,
3603
+ external_sale_number: normalizedData.external_sale_number || `LOCAL_DRAFT_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,
3604
+ created_at: createdAt,
3605
+ schedule_date: normalizedData.schedule_date || createdAt,
3606
+ need_sync: 0,
3607
+ is_draft_order: 1
3608
+ };
3609
+ if (!this.order || typeof this.order.upsertLocalDraftOrders !== "function") {
3610
+ this.logError(`${title}: Order 模块不支持本地草稿写入`);
3611
+ return {
3612
+ code: 500,
3613
+ status: false,
3614
+ message: "Order 模块不支持本地草稿写入",
3615
+ data: null
3616
+ };
3617
+ }
3618
+ try {
3619
+ await this.order.upsertLocalDraftOrders([draftOrder]);
3620
+ this.logInfo(`${title}: 草稿订单已写入本地`, {
3621
+ order_id: draftOrder.order_id,
3622
+ external_sale_number: draftOrder.external_sale_number
3623
+ });
3624
+ return {
3625
+ code: 200,
3626
+ status: true,
3627
+ message: "",
3628
+ data: {
3629
+ ...draftOrder,
3630
+ amount_gap: (_a = draftOrder == null ? void 0 : draftOrder.summary) == null ? void 0 : _a.amount_gap,
3631
+ expect_amount: (_b = draftOrder == null ? void 0 : draftOrder.summary) == null ? void 0 : _b.expect_amount,
3632
+ total_amount: (_c = draftOrder == null ? void 0 : draftOrder.summary) == null ? void 0 : _c.total_amount,
3633
+ payment_status: draftOrder == null ? void 0 : draftOrder.payment_status
3634
+ }
3635
+ };
3636
+ } catch (error) {
3637
+ const errorMessage = error instanceof Error ? error.message : String(error);
3638
+ this.logError(`${title}: 写入本地草稿订单失败`, {
3639
+ error: errorMessage
3640
+ });
3641
+ return { code: 500, status: false, message: errorMessage, data: null };
3642
+ }
3643
+ }
3217
3644
  async handlePendingSyncCheckoutOrder(params) {
3218
3645
  var _a, _b, _c, _d;
3219
3646
  const { backendPath, data, title, reason } = params;
@@ -3289,7 +3716,8 @@ var Server = class {
3289
3716
  return null;
3290
3717
  const pendingOrder = {
3291
3718
  ...data,
3292
- need_sync: 1
3719
+ need_sync: 1,
3720
+ is_draft_order: 0
3293
3721
  };
3294
3722
  const productMap = await this.buildSmallTicketProductMap(pendingOrder);
3295
3723
  const orderWithProductTitles = this.withPendingSyncProductTitles(
@@ -3342,7 +3770,7 @@ var Server = class {
3342
3770
  return 0;
3343
3771
  return payments.reduce((sum, payment) => {
3344
3772
  const status = String((payment == null ? void 0 : payment.status) || "").toLowerCase();
3345
- if (status === "voided" || status === "failed" || status === "cancelled")
3773
+ if (status !== "paid")
3346
3774
  return sum;
3347
3775
  return sum + this.toAmountNumber((payment == null ? void 0 : payment.amount) ?? (payment == null ? void 0 : payment.origin_amount));
3348
3776
  }, 0);
@@ -3909,9 +4337,11 @@ var Server = class {
3909
4337
  return value === void 0 ? void 0 : String(value);
3910
4338
  }
3911
4339
  buildCheckoutSyncSuccessPatch(fresh) {
4340
+ const patch = {
4341
+ is_draft_order: 0
4342
+ };
3912
4343
  if (!fresh)
3913
- return {};
3914
- const patch = {};
4344
+ return patch;
3915
4345
  if (fresh.order_id !== void 0 && fresh.order_id !== null)
3916
4346
  patch.order_id = fresh.order_id;
3917
4347
  if (fresh.order_number !== void 0 && fresh.order_number !== null) {
@@ -4277,14 +4707,8 @@ var Server = class {
4277
4707
  */
4278
4708
  async computeProductQueryResult(context, options) {
4279
4709
  const tTotal = performance.now();
4280
- const { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type, product_id, strategy_context } = context;
4710
+ const { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type, product_id } = context;
4281
4711
  const queryIds = Array.isArray(ids) ? ids.map((id) => Number(id)).filter((id) => Number.isFinite(id)) : [];
4282
- const formatterContext = this.buildProductFormatterContext({
4283
- schedule_date,
4284
- schedule_datetime,
4285
- customer_id,
4286
- strategy_context
4287
- });
4288
4712
  this.logInfo("computeProductQueryResult 开始", {
4289
4713
  menuListIdsCount: (menu_list_ids == null ? void 0 : menu_list_ids.length) ?? 0,
4290
4714
  ids: queryIds,
@@ -4293,17 +4717,20 @@ var Server = class {
4293
4717
  customer_id,
4294
4718
  extension_type,
4295
4719
  product_id,
4296
- strategyContextKeys: strategy_context ? Object.keys(strategy_context) : [],
4297
4720
  changedIds: options == null ? void 0 : options.changedIds
4298
4721
  });
4299
4722
  if (!this.products) {
4300
4723
  this.logError("computeProductQueryResult: Products 模块未注册");
4301
- return { message: "Products 模块未注册", data: this.buildProductQueryResultPayload([], 0) };
4724
+ return { message: "Products 模块未注册", data: { list: [], count: 0 } };
4302
4725
  }
4303
4726
  if (queryIds.length > 0) {
4304
4727
  const uniqueIds = Array.from(new Set(queryIds));
4305
4728
  const tPrice2 = performance.now();
4306
- const productsWithPrice = await this.products.getProductsWithPrice(schedule_date, formatterContext, {
4729
+ const productsWithPrice = await this.products.getProductsWithPrice(schedule_date, {
4730
+ scheduleModule: this.getSchedule(),
4731
+ schedule_datetime,
4732
+ customer_id
4733
+ }, {
4307
4734
  changedIds: options == null ? void 0 : options.changedIds,
4308
4735
  productIds: uniqueIds
4309
4736
  });
@@ -4324,7 +4751,7 @@ var Server = class {
4324
4751
  });
4325
4752
  return {
4326
4753
  code: 200,
4327
- data: this.buildProductQueryResultPayload(extensionFilteredProducts),
4754
+ data: { list: extensionFilteredProducts, count: extensionFilteredProducts.length },
4328
4755
  message: "",
4329
4756
  status: true
4330
4757
  };
@@ -4332,7 +4759,9 @@ var Server = class {
4332
4759
  if (product_id != null && Number.isFinite(Number(product_id))) {
4333
4760
  const pid = Number(product_id);
4334
4761
  const tPrice2 = performance.now();
4335
- const allProductsWithPrice = await this.products.getProductsWithPrice(schedule_date, formatterContext, {
4762
+ const allProductsWithPrice = await this.products.getProductsWithPrice(schedule_date, {
4763
+ scheduleModule: this.getSchedule()
4764
+ }, {
4336
4765
  changedIds: options == null ? void 0 : options.changedIds
4337
4766
  });
4338
4767
  (0, import_product.perfMark)("computeQuery.getProductsWithPrice(single)", performance.now() - tPrice2, {
@@ -4362,7 +4791,11 @@ var Server = class {
4362
4791
  }
4363
4792
  if (this.shouldQueryProductsByExtensionTypes(extension_type)) {
4364
4793
  const tPrice2 = performance.now();
4365
- let filteredProducts2 = await this.products.getProductsWithPrice(schedule_date, formatterContext, {
4794
+ let filteredProducts2 = await this.products.getProductsWithPrice(schedule_date, {
4795
+ scheduleModule: this.getSchedule(),
4796
+ schedule_datetime,
4797
+ customer_id
4798
+ }, {
4366
4799
  changedIds: options == null ? void 0 : options.changedIds
4367
4800
  });
4368
4801
  (0, import_product.perfMark)("computeQuery.getProductsWithPrice(extensionType)", performance.now() - tPrice2, {
@@ -4402,18 +4835,18 @@ var Server = class {
4402
4835
  });
4403
4836
  return {
4404
4837
  code: 200,
4405
- data: this.buildProductQueryResultPayload(filteredProducts2),
4838
+ data: { list: filteredProducts2, count: filteredProducts2.length },
4406
4839
  message: "",
4407
4840
  status: true
4408
4841
  };
4409
4842
  }
4410
4843
  if (!this.menu) {
4411
4844
  this.logError("computeProductQueryResult: Menu 模块未注册");
4412
- return { message: "Menu 模块未注册", data: this.buildProductQueryResultPayload([], 0) };
4845
+ return { message: "Menu 模块未注册", data: { list: [], count: 0 } };
4413
4846
  }
4414
4847
  if (!this.schedule) {
4415
4848
  this.logError("computeProductQueryResult: Schedule 模块未注册");
4416
- return { message: "Schedule 模块未注册", data: this.buildProductQueryResultPayload([], 0) };
4849
+ return { message: "Schedule 模块未注册", data: { list: [], count: 0 } };
4417
4850
  }
4418
4851
  let activeMenuList = [];
4419
4852
  if (menu_list_ids && Array.isArray(menu_list_ids) && menu_list_ids.length > 0) {
@@ -4437,7 +4870,11 @@ var Server = class {
4437
4870
  isAllProducts: !!productScope.isAllProducts
4438
4871
  });
4439
4872
  const tPrice = performance.now();
4440
- let filteredProducts = scopedProductIds.length > 0 ? await this.products.getProductsWithPrice(schedule_date, formatterContext, {
4873
+ let filteredProducts = scopedProductIds.length > 0 ? await this.products.getProductsWithPrice(schedule_date, {
4874
+ scheduleModule: this.getSchedule(),
4875
+ schedule_datetime,
4876
+ customer_id
4877
+ }, {
4441
4878
  changedIds: options == null ? void 0 : options.changedIds,
4442
4879
  productIds: productScope.isAllProducts ? void 0 : scopedProductIds
4443
4880
  }) : [];
@@ -4480,29 +4917,11 @@ var Server = class {
4480
4917
  });
4481
4918
  return {
4482
4919
  code: 200,
4483
- data: this.buildProductQueryResultPayload(filteredProducts),
4920
+ data: { list: filteredProducts, count: filteredProducts.length },
4484
4921
  message: "",
4485
4922
  status: true
4486
4923
  };
4487
4924
  }
4488
- /**
4489
- * 构建商品格式化上下文。
4490
- *
4491
- * 智能定价条件使用全量 menuList/scheduleList;Product Query 顶层参数只保留筛选商品集合所需字段。
4492
- */
4493
- buildProductFormatterContext(context) {
4494
- var _a, _b, _c, _d;
4495
- const scheduleModule = this.getSchedule();
4496
- return {
4497
- scheduleModule,
4498
- schedule_datetime: context.schedule_datetime,
4499
- customer_id: context.customer_id,
4500
- strategy_context: context.strategy_context,
4501
- menuList: ((_b = (_a = this.menu) == null ? void 0 : _a.getMenuList) == null ? void 0 : _b.call(_a)) || [],
4502
- scheduleList: ((_c = scheduleModule == null ? void 0 : scheduleModule.getScheduleList) == null ? void 0 : _c.call(scheduleModule)) || [],
4503
- dataVariantEvaluator: (_d = this.core.context) == null ? void 0 : _d.dataVariantEvaluator
4504
- };
4505
- }
4506
4925
  /**
4507
4926
  * 数据变更后,遍历所有订阅者重新计算查询结果并通过 callback 推送
4508
4927
  * 由 ProductsModule 的 onProductsSyncCompleted 事件触发