@pisell/pisellos 0.10.7 → 0.10.9

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 (124) hide show
  1. package/dist/core/index.js +0 -1
  2. package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
  3. package/dist/model/strategy/adapter/dataVariant/evaluator.js +287 -101
  4. package/dist/model/strategy/adapter/dataVariant/type.d.ts +25 -0
  5. package/dist/model/strategy/adapter/walletPass/evaluator.js +0 -2
  6. package/dist/model/strategy/adapter/walletPass/type.d.ts +5 -0
  7. package/dist/model/strategy/adapter/walletPass/utils.js +57 -26
  8. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +18 -12
  9. package/dist/modules/BookingContext/utils/productExtend.js +5 -9
  10. package/dist/modules/BookingContext/utils/timeSlices.js +24 -3
  11. package/dist/modules/Customer/index.d.ts +4 -0
  12. package/dist/modules/Customer/index.js +91 -59
  13. package/dist/modules/Customer/types.d.ts +2 -0
  14. package/dist/modules/Discount/index.d.ts +2 -0
  15. package/dist/modules/Discount/index.js +38 -5
  16. package/dist/modules/Discount/types.d.ts +11 -0
  17. package/dist/modules/Order/index.d.ts +32 -6
  18. package/dist/modules/Order/index.js +1165 -819
  19. package/dist/modules/Order/types.d.ts +32 -4
  20. package/dist/modules/Order/types.js +11 -0
  21. package/dist/modules/Order/utils/discountProductLineIdentity.d.ts +45 -0
  22. package/dist/modules/Order/utils/discountProductLineIdentity.js +227 -0
  23. package/dist/modules/Order/utils/virtualSettlement.d.ts +56 -0
  24. package/dist/modules/Order/utils/virtualSettlement.js +271 -0
  25. package/dist/modules/Order/utils.js +89 -48
  26. package/dist/modules/Payment/types.d.ts +2 -0
  27. package/dist/modules/Payment/utils.js +4 -1
  28. package/dist/modules/Payment/walletpass.d.ts +11 -0
  29. package/dist/modules/Payment/walletpass.js +235 -60
  30. package/dist/modules/Product/types.d.ts +23 -0
  31. package/dist/modules/ProductList/index.d.ts +15 -2
  32. package/dist/modules/ProductList/index.js +92 -13
  33. package/dist/modules/Rules/index.js +125 -52
  34. package/dist/modules/SalesSummary/index.d.ts +1 -0
  35. package/dist/modules/SalesSummary/index.js +4 -3
  36. package/dist/modules/SalesSummary/types.d.ts +1 -0
  37. package/dist/modules/SalesSummary/utils.d.ts +1 -0
  38. package/dist/modules/SalesSummary/utils.js +28 -2
  39. package/dist/server/index.d.ts +15 -0
  40. package/dist/server/index.js +894 -781
  41. package/dist/server/modules/order/index.d.ts +2 -0
  42. package/dist/server/modules/order/index.js +261 -96
  43. package/dist/server/modules/order/types.d.ts +1 -1
  44. package/dist/server/utils/small-ticket.js +2 -1
  45. package/dist/solution/BaseSales/index.d.ts +41 -7
  46. package/dist/solution/BaseSales/index.js +1405 -974
  47. package/dist/solution/BaseSales/utils/cartPromotion.js +26 -3
  48. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  49. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +79 -13
  50. package/dist/solution/BaseSales/utils.js +31 -20
  51. package/dist/solution/BookingByStep/index.d.ts +3 -3
  52. package/dist/solution/BookingTicket/index.d.ts +5 -1
  53. package/dist/solution/BookingTicket/index.js +221 -162
  54. package/dist/solution/BookingTicket/types.d.ts +3 -0
  55. package/dist/solution/BookingTicket/utils/addProductDecision.js +2 -1
  56. package/dist/solution/BookingTicket/utils/cartView.js +44 -32
  57. package/dist/solution/Sales/index.d.ts +1 -0
  58. package/dist/solution/Sales/index.js +16 -2
  59. package/dist/solution/ScanOrder/index.js +25 -64
  60. package/dist/solution/ScanOrder/utils.js +31 -20
  61. package/dist/solution/UnifiedBookingSales/index.d.ts +5 -4
  62. package/dist/solution/UnifiedBookingSales/index.js +51 -39
  63. package/lib/core/index.js +0 -1
  64. package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
  65. package/lib/model/strategy/adapter/dataVariant/evaluator.js +170 -7
  66. package/lib/model/strategy/adapter/dataVariant/type.d.ts +25 -0
  67. package/lib/model/strategy/adapter/walletPass/evaluator.js +0 -2
  68. package/lib/model/strategy/adapter/walletPass/type.d.ts +5 -0
  69. package/lib/model/strategy/adapter/walletPass/utils.js +62 -11
  70. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +6 -1
  71. package/lib/modules/BookingContext/utils/productExtend.js +4 -3
  72. package/lib/modules/BookingContext/utils/timeSlices.js +18 -3
  73. package/lib/modules/Customer/index.d.ts +4 -0
  74. package/lib/modules/Customer/index.js +11 -0
  75. package/lib/modules/Customer/types.d.ts +2 -0
  76. package/lib/modules/Discount/index.d.ts +2 -0
  77. package/lib/modules/Discount/index.js +37 -3
  78. package/lib/modules/Discount/types.d.ts +11 -0
  79. package/lib/modules/Order/index.d.ts +32 -6
  80. package/lib/modules/Order/index.js +518 -148
  81. package/lib/modules/Order/types.d.ts +32 -4
  82. package/lib/modules/Order/utils/discountProductLineIdentity.d.ts +45 -0
  83. package/lib/modules/Order/utils/discountProductLineIdentity.js +170 -0
  84. package/lib/modules/Order/utils/virtualSettlement.d.ts +56 -0
  85. package/lib/modules/Order/utils/virtualSettlement.js +300 -0
  86. package/lib/modules/Order/utils.js +65 -21
  87. package/lib/modules/Payment/types.d.ts +2 -0
  88. package/lib/modules/Payment/utils.js +5 -1
  89. package/lib/modules/Payment/walletpass.d.ts +11 -0
  90. package/lib/modules/Payment/walletpass.js +198 -17
  91. package/lib/modules/Product/types.d.ts +23 -0
  92. package/lib/modules/ProductList/index.d.ts +15 -2
  93. package/lib/modules/ProductList/index.js +85 -3
  94. package/lib/modules/Rules/index.js +100 -20
  95. package/lib/modules/SalesSummary/index.d.ts +1 -0
  96. package/lib/modules/SalesSummary/index.js +10 -2
  97. package/lib/modules/SalesSummary/types.d.ts +1 -0
  98. package/lib/modules/SalesSummary/utils.d.ts +1 -0
  99. package/lib/modules/SalesSummary/utils.js +30 -2
  100. package/lib/server/index.d.ts +15 -0
  101. package/lib/server/index.js +105 -14
  102. package/lib/server/modules/order/index.d.ts +2 -0
  103. package/lib/server/modules/order/index.js +75 -5
  104. package/lib/server/modules/order/types.d.ts +1 -1
  105. package/lib/server/utils/small-ticket.js +1 -1
  106. package/lib/solution/BaseSales/index.d.ts +41 -7
  107. package/lib/solution/BaseSales/index.js +325 -39
  108. package/lib/solution/BaseSales/utils/cartPromotion.js +26 -2
  109. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  110. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +62 -12
  111. package/lib/solution/BaseSales/utils.js +29 -18
  112. package/lib/solution/BookingByStep/index.d.ts +3 -3
  113. package/lib/solution/BookingTicket/index.d.ts +5 -1
  114. package/lib/solution/BookingTicket/index.js +31 -6
  115. package/lib/solution/BookingTicket/types.d.ts +3 -0
  116. package/lib/solution/BookingTicket/utils/addProductDecision.js +2 -1
  117. package/lib/solution/BookingTicket/utils/cartView.js +43 -30
  118. package/lib/solution/Sales/index.d.ts +1 -0
  119. package/lib/solution/Sales/index.js +15 -3
  120. package/lib/solution/ScanOrder/index.js +17 -54
  121. package/lib/solution/ScanOrder/utils.js +29 -18
  122. package/lib/solution/UnifiedBookingSales/index.d.ts +5 -4
  123. package/lib/solution/UnifiedBookingSales/index.js +35 -26
  124. package/package.json +1 -1
@@ -45,6 +45,7 @@ var import_floor_plan = require("./modules/floor-plan");
45
45
  var import_types = require("./modules/floor-plan/types");
46
46
  var import_payment = require("./modules/payment");
47
47
  var import_schedule2 = require("./utils/schedule");
48
+ var import_time = require("./utils/time");
48
49
  var import_types2 = require("./modules/products/types");
49
50
  var import_product = require("./utils/product");
50
51
  var import_order = require("./modules/order");
@@ -65,6 +66,7 @@ var PRODUCT_TITLE_SNAPSHOT_KEYS = [
65
66
  "kitchen",
66
67
  "original"
67
68
  ];
69
+ var AUTO_PRINT_STORAGE_KEY = "auto_print";
68
70
  var Server = class {
69
71
  constructor(core) {
70
72
  this.quotationAvailableCache = /* @__PURE__ */ new Map();
@@ -254,7 +256,11 @@ var Server = class {
254
256
  strategy_context
255
257
  });
256
258
  if (subscriberId && typeof callback === "function") {
257
- this.syncProductQueryScheduleTimers(subscriberId, strategy_context);
259
+ this.syncProductQueryScheduleTimers({
260
+ subscriberId,
261
+ menu_list_ids,
262
+ strategy_context
263
+ });
258
264
  }
259
265
  return result;
260
266
  };
@@ -1081,7 +1087,12 @@ var Server = class {
1081
1087
  };
1082
1088
  }
1083
1089
  try {
1084
- const menuList = this.menu.getMenuByIds(menu_list_ids);
1090
+ const {
1091
+ menuList,
1092
+ scheduleIds,
1093
+ scheduleList,
1094
+ timePoints
1095
+ } = this.getMenuScheduleTimePoints(menu_list_ids);
1085
1096
  console.log(`[Server] 找到 ${menuList.length} 个餐牌`);
1086
1097
  this.logInfo("handleGetScheduleTimePoints: 获取到餐牌列表", {
1087
1098
  requestedCount: menu_list_ids.length,
@@ -1089,7 +1100,6 @@ var Server = class {
1089
1100
  menu_list_ids,
1090
1101
  menuList
1091
1102
  });
1092
- const scheduleIds = (0, import_schedule2.extractScheduleIdsFromMenus)(menuList);
1093
1103
  console.log(`[Server] 提取到 ${scheduleIds.length} 个日程ID:`, scheduleIds);
1094
1104
  this.logInfo("handleGetScheduleTimePoints: 提取到日程 IDs", {
1095
1105
  scheduleCount: scheduleIds.length
@@ -1103,13 +1113,11 @@ var Server = class {
1103
1113
  status: true
1104
1114
  };
1105
1115
  }
1106
- const scheduleList = this.schedule.getScheduleByIds(scheduleIds);
1107
1116
  console.log(`[Server] 找到 ${scheduleList.length} 个日程`);
1108
1117
  this.logInfo("handleGetScheduleTimePoints: 获取到日程详情", {
1109
1118
  requestedCount: scheduleIds.length,
1110
1119
  foundCount: scheduleList.length
1111
1120
  });
1112
- const timePoints = (0, import_schedule2.extractTimePointsFromSchedules)(scheduleList);
1113
1121
  console.log(`[Server] 提取到 ${timePoints.length} 个时间点:`, timePoints);
1114
1122
  this.logInfo("handleGetScheduleTimePoints 处理完成", {
1115
1123
  menuListIdsCount: menu_list_ids.length,
@@ -1789,6 +1797,57 @@ var Server = class {
1789
1797
  });
1790
1798
  }
1791
1799
  }
1800
+ /**
1801
+ * 编辑正式订单时强制查询 Server 最新快照并覆盖本地缓存。
1802
+ * 商品成员增删由 OrderModule 在 SQLite/Store 更新完成后广播,
1803
+ * UI 可复用 order:onRemoteProductMembershipChanged 处理冲突。
1804
+ */
1805
+ async checkRemoteOrderProductMembership(orderId) {
1806
+ const normalizedOrderId = String(orderId ?? "").trim();
1807
+ if (!normalizedOrderId || normalizedOrderId.startsWith("local_order")) {
1808
+ this.logInfo("checkRemoteOrderProductMembership: 跳过非正式订单", {
1809
+ orderId
1810
+ });
1811
+ return;
1812
+ }
1813
+ if (!this.order) {
1814
+ const error = new Error("Order 模块未注册");
1815
+ this.logWarning("checkRemoteOrderProductMembership: Order 模块未注册", {
1816
+ orderId: normalizedOrderId
1817
+ });
1818
+ throw error;
1819
+ }
1820
+ this.logInfo("checkRemoteOrderProductMembership 开始", {
1821
+ orderId: normalizedOrderId
1822
+ });
1823
+ const startTime = Date.now();
1824
+ try {
1825
+ const freshOrders = await this.order.fetchOrdersByHttp([
1826
+ normalizedOrderId
1827
+ ]);
1828
+ const freshOrder = freshOrders.find(
1829
+ (order) => String(order == null ? void 0 : order.order_id) === normalizedOrderId
1830
+ );
1831
+ if (!freshOrder) {
1832
+ throw new Error("Server 未返回目标订单最新快照");
1833
+ }
1834
+ await this.order.upsertOrdersFromRemote(
1835
+ [freshOrder],
1836
+ "manual.editOpenRemoteCheck"
1837
+ );
1838
+ this.logInfo("checkRemoteOrderProductMembership 完成", {
1839
+ orderId: normalizedOrderId,
1840
+ duration: `${Date.now() - startTime}ms`
1841
+ });
1842
+ } catch (error) {
1843
+ this.logError("checkRemoteOrderProductMembership 失败", {
1844
+ orderId: normalizedOrderId,
1845
+ duration: `${Date.now() - startTime}ms`,
1846
+ error: error instanceof Error ? error.message : String(error)
1847
+ });
1848
+ throw error;
1849
+ }
1850
+ }
1792
1851
  /**
1793
1852
  * 清空所有server模块的IndexedDB缓存
1794
1853
  * @returns Promise<void>
@@ -2268,16 +2327,44 @@ var Server = class {
2268
2327
  });
2269
2328
  }
2270
2329
  }
2330
+ /**
2331
+ * 根据餐牌 ID 获取其绑定日程中的全部时间点。
2332
+ * 商品查询定时器与 schedule-time-points 路由共用此逻辑。
2333
+ */
2334
+ getMenuScheduleTimePoints(menuListIds) {
2335
+ var _a, _b;
2336
+ const menuList = ((_a = this.menu) == null ? void 0 : _a.getMenuByIds(menuListIds)) ?? [];
2337
+ const scheduleIds = (0, import_schedule2.extractScheduleIdsFromMenus)(menuList);
2338
+ const scheduleList = scheduleIds.length > 0 ? ((_b = this.schedule) == null ? void 0 : _b.getScheduleByIds(scheduleIds)) ?? [] : [];
2339
+ const timePoints = (0, import_schedule2.extractTimePointsFromSchedules)(scheduleList);
2340
+ return {
2341
+ menuList,
2342
+ scheduleIds,
2343
+ scheduleList,
2344
+ timePoints
2345
+ };
2346
+ }
2271
2347
  /**
2272
2348
  * query 完成后为 subscriber 同步 schedule 定时器(先 clear 再 schedule)。
2273
2349
  */
2274
- syncProductQueryScheduleTimers(subscriberId, strategy_context) {
2350
+ syncProductQueryScheduleTimers({
2351
+ subscriberId,
2352
+ menu_list_ids,
2353
+ strategy_context
2354
+ }) {
2275
2355
  var _a, _b;
2276
2356
  this.clearSubscriberScheduleTimers(subscriberId);
2277
2357
  if (!this.shouldScheduleProductQueryReload(strategy_context)) {
2278
2358
  return;
2279
2359
  }
2280
- const timePoints = ((_b = (_a = this.products) == null ? void 0 : _a.getLastScheduleTimePoints) == null ? void 0 : _b.call(_a)) ?? [];
2360
+ const productTimePoints = ((_b = (_a = this.products) == null ? void 0 : _a.getLastScheduleTimePoints) == null ? void 0 : _b.call(_a)) ?? [];
2361
+ const menuListIds = Array.isArray(menu_list_ids) ? Array.from(new Set(
2362
+ menu_list_ids.map((id) => Number(id)).filter((id) => Number.isFinite(id))
2363
+ )) : [];
2364
+ const menuTimePoints = this.getMenuScheduleTimePoints(menuListIds).timePoints;
2365
+ const timePoints = (0, import_time.sortTimePoints)(
2366
+ Array.from(/* @__PURE__ */ new Set([...productTimePoints, ...menuTimePoints]))
2367
+ );
2281
2368
  if (timePoints.length > 0) {
2282
2369
  this.scheduleSubscriberTimePointReloads(subscriberId, timePoints);
2283
2370
  }
@@ -3740,7 +3827,6 @@ var Server = class {
3740
3827
  });
3741
3828
  }
3742
3829
  async handleOrderCheckoutSubmit(params) {
3743
- var _a;
3744
3830
  const { backendPath, data, title } = params;
3745
3831
  this.logInfo(`${title}: 开始处理`, {
3746
3832
  backendPath,
@@ -3765,10 +3851,7 @@ var Server = class {
3765
3851
  });
3766
3852
  if ((pendingResult == null ? void 0 : pendingResult.status) === true) {
3767
3853
  const pendingOrder = pendingResult.data;
3768
- const platform = (_a = this.core.context) == null ? void 0 : _a.getPlatform();
3769
- const isAndroid = platform === "android";
3770
- if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData) && this.isSalesOrderFullyPaid(pendingOrder) && // TODO 这里先加个兼容,如果是安卓,则需要 type=virtual 才走打印,如果是苹果则无限制
3771
- (isAndroid ? checkoutData.type === "virtual" : true)) {
3854
+ if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData) && this.isSalesOrderFullyPaid(pendingOrder) && this.shouldAutoPrintCheckoutReceipt()) {
3772
3855
  await this.dispatchLocalReceiptPrint({
3773
3856
  checkoutData,
3774
3857
  order: pendingOrder,
@@ -3831,9 +3914,8 @@ var Server = class {
3831
3914
  checkoutData: syncResult.checkoutData,
3832
3915
  order: syncedOrder,
3833
3916
  response: syncResult.normalizedResponse,
3834
- requireFullyPaid: true,
3917
+ requireFullyPaid: true
3835
3918
  // print_all 的 type=0 是收据打印;不要沿用同步成功后的券/手环打印 type=99。
3836
- isManualPrint: true
3837
3919
  });
3838
3920
  }
3839
3921
  return response;
@@ -4003,6 +4085,15 @@ var Server = class {
4003
4085
  { requireFullyPaid: true, productMap }
4004
4086
  );
4005
4087
  }
4088
+ /**
4089
+ * Android 结账自动小票由当前设备设置控制;其它平台保持原有行为。
4090
+ */
4091
+ shouldAutoPrintCheckoutReceipt() {
4092
+ var _a, _b, _c, _d, _e;
4093
+ if (((_b = (_a = this.core.context) == null ? void 0 : _a.getPlatform) == null ? void 0 : _b.call(_a)) !== "android")
4094
+ return true;
4095
+ return ((_e = (_d = (_c = this.app) == null ? void 0 : _c.storage) == null ? void 0 : _d.getStorage) == null ? void 0 : _e.call(_d, AUTO_PRINT_STORAGE_KEY)) !== "false";
4096
+ }
4006
4097
  shouldBuildSmallTicketData(order) {
4007
4098
  if (!order || typeof order !== "object")
4008
4099
  return false;
@@ -235,6 +235,7 @@ export declare class OrderModule extends BaseModule implements Module {
235
235
  */
236
236
  private lookupOrderIndexByIdentityKeys;
237
237
  private isRemoteEchoMergeSource;
238
+ private isRemoteProductMembershipChangeSource;
238
239
  private getProductMembershipKey;
239
240
  private doProductsHaveStableMembershipIdentity;
240
241
  /**
@@ -273,6 +274,7 @@ export declare class OrderModule extends BaseModule implements Module {
273
274
  * // => 'S-1001'
274
275
  */
275
276
  private getOrderStorageKey;
277
+ private getPersistedOrderStorageKey;
276
278
  private getOrderIdentityMatchKeys;
277
279
  private doOrdersShareIdentity;
278
280
  private findOrderIndexByIdentity;
@@ -39,6 +39,7 @@ var import_orderCollectionIdentity = require("../../../modules/Order/utils/order
39
39
  var import_types = require("./types");
40
40
  var import_payment_utils = require("../../../modules/Order/payment-utils");
41
41
  var INDEXDB_STORE_NAME = "orders";
42
+ var ORDER_STORAGE_KEY_FIELD = "__order_storage_key";
42
43
  var ORDER_LAST_FULL_FETCH_AT_STORAGE_KEY = "server_order_last_full_fetch_at";
43
44
  var ORDER_SYNC_THROTTLE_MS_STORAGE_KEY = "order_sync_throttle_ms";
44
45
  var DEFAULT_ORDER_SYNC_THROTTLE_MS = 2e3;
@@ -920,10 +921,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
920
921
  */
921
922
  async upsertOrdersFromRemote(freshOrders, source = "upsertOrdersFromRemote") {
922
923
  if (!(freshOrders == null ? void 0 : freshOrders.length)) {
923
- this.logInfo("upsertOrdersFromRemote-订单列表为空", {});
924
+ this.logInfo("upsertOrdersFromRemote-订单列表为空", { source });
924
925
  return;
925
926
  }
926
- this.logInfo("upsertOrdersFromRemote-开始", { count: freshOrders.length, source });
927
+ this.logInfo("upsertOrdersFromRemote-开始", {
928
+ count: freshOrders.length,
929
+ source
930
+ });
927
931
  await this.mergeOrdersToStore(freshOrders, source);
928
932
  }
929
933
  async markOrderSyncedByExternalSaleNumber(params) {
@@ -1530,6 +1534,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1530
1534
  const patchedOrders = [];
1531
1535
  const remoteProductMembershipChanges = [];
1532
1536
  const forceWriteStorageKeys = /* @__PURE__ */ new Set();
1537
+ const storageKeyMigrations = [];
1533
1538
  const mergeActions = {};
1534
1539
  const existingProductsHaveStableIdentity = this.store.list.map(
1535
1540
  (order) => this.doProductsHaveStableMembershipIdentity(
@@ -1554,6 +1559,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1554
1559
  const mergeKey = storageKey || (fresh.order_id !== void 0 && fresh.order_id !== null ? this.getIdKey(fresh.order_id) : "");
1555
1560
  if (matchIndex >= 0) {
1556
1561
  const existingOrder = updatedList[matchIndex];
1562
+ const previousStorageKey = this.getPersistedOrderStorageKey(existingOrder);
1557
1563
  if (this.isPendingSyncOrder(existingOrder) && this.isRemoteEchoMergeSource(source)) {
1558
1564
  this.logInfo("mergeOrdersToStore-跳过 pending 订单远端覆盖", {
1559
1565
  source,
@@ -1615,6 +1621,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1615
1621
  }
1616
1622
  }
1617
1623
  }
1624
+ const nextStorageKey = this.getOrderStorageKey(mergedOrder);
1625
+ if (previousStorageKey && nextStorageKey && previousStorageKey !== nextStorageKey) {
1626
+ storageKeyMigrations.push({
1627
+ orderId: mergedOrder.order_id ?? existingOrder.order_id ?? fresh.order_id ?? null,
1628
+ from: previousStorageKey,
1629
+ to: nextStorageKey
1630
+ });
1631
+ }
1618
1632
  updatedList[adjustedMatchIndex] = mergedOrder;
1619
1633
  existingProductsHaveStableIdentity[adjustedMatchIndex] = mergedProductsHaveStableIdentity;
1620
1634
  if (membershipChange) {
@@ -1652,7 +1666,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1652
1666
  patchedOrders,
1653
1667
  source,
1654
1668
  mergeActions,
1655
- {},
1669
+ { storageKeyMigrations },
1656
1670
  forceWriteStorageKeys
1657
1671
  );
1658
1672
  this.logInfo("mergeOrdersToStore-结束", {
@@ -1685,6 +1699,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1685
1699
  isRemoteEchoMergeSource(source) {
1686
1700
  return source === "pubsub.bodyUpsert" || source === "pubsub.httpRefresh";
1687
1701
  }
1702
+ isRemoteProductMembershipChangeSource(source) {
1703
+ return this.isRemoteEchoMergeSource(source) || source === "manual.editOpenRemoteCheck";
1704
+ }
1688
1705
  getProductMembershipKey(product) {
1689
1706
  const persistentId = (0, import_orderCollectionIdentity.getOrderCollectionPersistentId)("product", product);
1690
1707
  if (persistentId)
@@ -1717,7 +1734,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1717
1734
  * 对比合并前后的商品成员集合。商品字段修改与数组重排不会产生 diff。
1718
1735
  */
1719
1736
  getRemoteProductMembershipChange(existingOrder, mergedOrder, source) {
1720
- if (!this.isRemoteEchoMergeSource(source))
1737
+ if (!this.isRemoteProductMembershipChangeSource(source))
1721
1738
  return null;
1722
1739
  const previousProducts = Array.isArray(existingOrder.products) ? existingOrder.products : [];
1723
1740
  const currentProducts = Array.isArray(mergedOrder.products) ? mergedOrder.products : [];
@@ -1854,6 +1871,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1854
1871
  }
1855
1872
  return "";
1856
1873
  }
1874
+ getPersistedOrderStorageKey(order) {
1875
+ const persistedStorageKey = order == null ? void 0 : order[ORDER_STORAGE_KEY_FIELD];
1876
+ if (persistedStorageKey !== void 0 && persistedStorageKey !== null && persistedStorageKey !== "") {
1877
+ return String(persistedStorageKey);
1878
+ }
1879
+ return this.getOrderStorageKey(order);
1880
+ }
1857
1881
  getOrderIdentityMatchKeys(order) {
1858
1882
  return this.getOrderIdentityEntries(order).map((entry) => `${entry.field}:${entry.key}`);
1859
1883
  }
@@ -2284,7 +2308,18 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2284
2308
  throw new Error("订单 SQLite 数据库未初始化");
2285
2309
  return;
2286
2310
  }
2287
- const ordersSnapshot = (0, import_lodash_es.cloneDeep)(orders).map((order) => this.normalizeOrderCollectionsForIngress(order, `${source}.sqliteIngress`)).filter((order) => this.getOrderStorageKey(order));
2311
+ const migrationTargetStorageKeys = new Set(
2312
+ (options.storageKeyMigrations || []).map((migration) => migration.to)
2313
+ );
2314
+ const ordersSnapshot = (0, import_lodash_es.cloneDeep)(orders).map((order) => this.normalizeOrderCollectionsForIngress(order, `${source}.sqliteIngress`)).map((order) => {
2315
+ const storageKey = this.getOrderStorageKey(order);
2316
+ if (!storageKey || !migrationTargetStorageKeys.has(storageKey))
2317
+ return order;
2318
+ return {
2319
+ ...order,
2320
+ [ORDER_STORAGE_KEY_FIELD]: storageKey
2321
+ };
2322
+ }).filter((order) => this.getOrderStorageKey(order));
2288
2323
  if (ordersSnapshot.length === 0) {
2289
2324
  return;
2290
2325
  }
@@ -2301,6 +2336,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2301
2336
  if (compactedToWrite.length === 0) {
2302
2337
  return;
2303
2338
  }
2339
+ const writtenStorageKeys = new Set(
2340
+ compactedToWrite.map((order) => this.getOrderStorageKey(order)).filter(Boolean)
2341
+ );
2342
+ const storageKeyMigrations = /* @__PURE__ */ new Map();
2343
+ for (const migration of options.storageKeyMigrations || []) {
2344
+ if (!writtenStorageKeys.has(migration.to))
2345
+ continue;
2346
+ if (writtenStorageKeys.has(migration.from))
2347
+ continue;
2348
+ storageKeyMigrations.set(migration.from, migration);
2349
+ }
2304
2350
  try {
2305
2351
  await this.runInOrderSQLiteSaveQueue(async () => {
2306
2352
  let writeMethod = "none";
@@ -2324,6 +2370,30 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2324
2370
  throw new Error("订单 SQLite 数据库不支持写入");
2325
2371
  }
2326
2372
  this.recordRecentSqliteWrite(source, compactedToWrite);
2373
+ if (writeMethod !== "none") {
2374
+ for (const migration of storageKeyMigrations.values()) {
2375
+ try {
2376
+ await this.dbManager.delete(INDEXDB_STORE_NAME, migration.from);
2377
+ this.recentSqliteWriteByStorageKey.delete(migration.from);
2378
+ for (const order of orders) {
2379
+ if (this.getOrderStorageKey(order) !== migration.to)
2380
+ continue;
2381
+ const orderRecord = order;
2382
+ if (String(orderRecord[ORDER_STORAGE_KEY_FIELD] ?? "") !== migration.from)
2383
+ continue;
2384
+ orderRecord[ORDER_STORAGE_KEY_FIELD] = migration.to;
2385
+ }
2386
+ } catch (error) {
2387
+ this.logError("删除订单旧 SQLite storage key 失败", {
2388
+ source,
2389
+ order_id: migration.orderId,
2390
+ oldStorageKey: migration.from,
2391
+ newStorageKey: migration.to,
2392
+ error: error instanceof Error ? error.message : String(error)
2393
+ });
2394
+ }
2395
+ }
2396
+ }
2327
2397
  this.logInfo("patchOrdersInSQLite-完成", {
2328
2398
  source,
2329
2399
  count: compactedToWrite.length,
@@ -568,7 +568,7 @@ export interface OrderChangedPayload {
568
568
  /** 触发来源,便于订阅者区分 pubsub / 远端覆盖 / 清空等场景 */
569
569
  source?: string;
570
570
  }
571
- export type RemoteProductMembershipChangeSource = 'pubsub.bodyUpsert' | 'pubsub.httpRefresh';
571
+ export type RemoteProductMembershipChangeSource = 'pubsub.bodyUpsert' | 'pubsub.httpRefresh' | 'manual.editOpenRemoteCheck';
572
572
  /**
573
573
  * 远端订单快照相对本地订单产生商品成员增删时的广播载荷。
574
574
  * 只表达商品行成员关系变化,不包含数量、价格、备注等字段级修改。
@@ -562,7 +562,7 @@ function buildOptionTitleSuffix(options) {
562
562
  function formatBundlePrice(bundle, currencySymbol) {
563
563
  const value = bundle.bundle_selling_price ?? bundle.bundle_sum_price ?? bundle.price ?? 0;
564
564
  const amount = new import_decimal.default(toMoneyNumber(value));
565
- const isNegative = bundle.price_type === "markdown" || bundle.price_type === "markup" && bundle.price_type_ext === "product_price";
565
+ const isNegative = bundle.price_type === "markdown";
566
566
  if (isNegative)
567
567
  return `-${currencySymbol}${amount.abs().toFixed(2)}`;
568
568
  return formatMoney(amount, currencySymbol);
@@ -2,9 +2,9 @@ import { Module, ModuleOptions, PisellCore } from '../../types';
2
2
  import { BaseModule } from '../../modules/BaseModule';
3
3
  import { BaseSalesOrderProduct, BaseSalesOrderProductIdentity, BaseSalesPaymentStatus, BaseSalesUpdateOrderProductQuantityParams, BaseSalesCalculateProductBookingPriceParams, BaseSalesPriceRecalculationContextChange, BaseSalesProductBookingPriceResult, BaseSalesQuotationCustomerScopeInfo, BaseSalesScanCodeResult, BaseSalesCashPaymentConfig, BaseSalesPayCashParams, BaseSalesPayCashResult, BaseSalesCommitPaymentMethodParams, BaseSalesCommitPaymentMethodResult, BaseSalesConfirmWalletPaymentResult } from './types';
4
4
  import { OrderModule } from '../../modules/Order';
5
- import type { AddProductBookingInput, LoadSalesDetailParams, OrderPaymentData, OrderPaymentUpdateOptions, OrderPaymentUpdateResult, OrderPaymentSource, SendCustomerPayLinkParams, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, UpdateTempOrderCustomerInput, UpdateOrderBookingParams, UpdateOrderProductParams, OrderTempOrder, OrderSummary, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions } from '../../modules/Order/types';
5
+ import type { AddProductBookingInput, AddProductToOrderOptions, LoadSalesDetailParams, OrderPaymentData, OrderPaymentUpdateOptions, OrderPaymentUpdateResult, OrderPaymentSource, SendCustomerPayLinkParams, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, UpdateTempOrderCustomerInput, UpdateOrderBookingParams, UpdateOrderProductParams, OrderTempOrder, OrderSummary, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions, RemoveProductsFromOrderOptions, ReplaceTempOrderOptions } from '../../modules/Order/types';
6
6
  import type { SubmitPayloadEnhancer } from '../../modules/Order/utils';
7
- import type { Discount } from '../../modules/Discount/types';
7
+ import type { Discount, VirtualCurrencyAsset } from '../../modules/Discount/types';
8
8
  import { RequestPlugin, WindowPlugin } from '../../plugins';
9
9
  export * from './types';
10
10
  import { ProductList } from '../../modules/ProductList';
@@ -109,6 +109,25 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
109
109
  private applyQuotationScheduleResolver;
110
110
  private loadQuotationForPriceQuery;
111
111
  private getPriceQueryProductId;
112
+ /**
113
+ * Change Time / customer reprice 必须沿用商品列表的渠道口径。
114
+ * SalesSdk Provider 通常将渠道存为 platform,因此不能只读取 otherParams.channel。
115
+ */
116
+ private getPriceQueryChannel;
117
+ /**
118
+ * /product/query 的智能定价评估只读取 strategy_context;
119
+ * application_code 仅作为接口兼容字段,不能替代 channel / business_code。
120
+ */
121
+ private getPriceQueryStrategyContext;
122
+ /**
123
+ * 子类可在商品重报价前准备客户维度的策略上下文,例如等待 Wallet/优惠资产加载。
124
+ */
125
+ protected prepareProductPriceQueryContext(_customerId?: number | string): Promise<void>;
126
+ /**
127
+ * 默认保留 BaseSales 的 legacy quotation 行为;已由 /product/query 统一完成
128
+ * 智能定价与报价合并的业务可在子类中覆盖,避免二次覆盖权威价格。
129
+ */
130
+ protected preferAuthoritativeProductQueryPrice(): boolean;
112
131
  private getPriceQuerySchedule;
113
132
  private loadProductsForPriceQuery;
114
133
  private loadProductForPriceQuery;
@@ -156,6 +175,9 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
156
175
  protected setPaymentNumberDevicePrefix(prefix: unknown): void;
157
176
  private getPaymentNumberDevicePrefixSync;
158
177
  private getPaymentNumberDevicePrefixAsync;
178
+ private isMultiCurrencySettlementEnabled;
179
+ private isActiveVirtualSettlementOrder;
180
+ private isHistoricalVirtualSettlementOrder;
159
181
  private syncAppDataToTempOrder;
160
182
  initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
161
183
  destroy(): Promise<void>;
@@ -182,7 +204,7 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
182
204
  /** 获取附加费用(运费/服务费/税费等)。 */
183
205
  getSurcharges(): ISalesSurcharge[];
184
206
  getTempOrder(): OrderTempOrder | null;
185
- replaceTempOrder(tempOrder: OrderTempOrder): Promise<OrderTempOrder>;
207
+ replaceTempOrder(tempOrder: OrderTempOrder, options?: ReplaceTempOrderOptions): Promise<OrderTempOrder>;
186
208
  getOrderIdentity(): import("../../modules/Order/types").OrderIdentitySnapshot | null;
187
209
  getOrderSnapshot(): import("../../modules/Order/types").OrderSnapshot | null;
188
210
  getOrderSyncState(): import("../../modules/Order/types").OrderSyncState;
@@ -208,6 +230,8 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
208
230
  * 同步清空内存中的 salesDetail 商品/预约视图,避免编辑态仍读到旧 bookings。
209
231
  */
210
232
  clearOrderCartLines(): Promise<OrderTempOrder>;
233
+ /** 切换法币 / WalletPass 单位时清空商品、折扣与支付状态,保留客户。 */
234
+ clearOrderForSettlementSwitch(): Promise<OrderTempOrder>;
211
235
  getOrderProducts(): import("../../modules/Order/types").OrderProduct[];
212
236
  getSummary(): Promise<OrderSummary>;
213
237
  private getHistoricalProductDiscountList;
@@ -218,12 +242,15 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
218
242
  loadDiscountConfig(params?: {
219
243
  customerId?: number;
220
244
  action?: 'create' | 'edit';
245
+ force?: boolean;
221
246
  }): Promise<{
222
247
  productList: Record<string, any>[];
223
248
  discountList: Discount[];
224
249
  availableWalletIds: number[];
250
+ virtualCurrencyList: VirtualCurrencyAsset[];
225
251
  }>;
226
252
  getAvailableWalletIds(): number[];
253
+ getVirtualCurrencyList(): VirtualCurrencyAsset[];
227
254
  bestDiscount(cb?: (result: any) => void): Promise<{
228
255
  productList: Record<string, any>[];
229
256
  discountList: Discount[];
@@ -255,6 +282,7 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
255
282
  confirmPendingVoucherPayments?: boolean;
256
283
  enhancePayload?: SubmitPayloadEnhancer;
257
284
  }): Promise<T>;
285
+ private buildVirtualSettlementSubmitData;
258
286
  /**
259
287
  * 提交当前 Sales 订单。
260
288
  *
@@ -354,6 +382,11 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
354
382
  selected: boolean;
355
383
  source?: WalletAssetSelectionSource;
356
384
  }): Promise<WalletAssetsState>;
385
+ /** 更新已选钱包资产的手动使用金额,并同步 pending payment。 */
386
+ updateWalletAssetAmount(params: {
387
+ assetId: WalletAssetId;
388
+ amount: number;
389
+ }): Promise<WalletAssetsState>;
357
390
  /** 扫码精确查券;仅可用资产会被自动选中。 */
358
391
  scanWalletAsset(code: string): Promise<ScanWalletAssetResult>;
359
392
  /** 清空全部未确认钱包选择,已支付钱包项由 Order 模块继续保留。 */
@@ -421,9 +454,10 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
421
454
  transformBaseProductToOrderProduct(params: TransformBaseProductToOrderProductParams): import("./utils/transformBaseProductToOrderProduct").BaseProductOrderProductInput | null;
422
455
  calculateProductBookingPrice(params: BaseSalesCalculateProductBookingPriceParams): Promise<BaseSalesProductBookingPriceResult>;
423
456
  getQuotationCustomerScopeInfo(): BaseSalesQuotationCustomerScopeInfo;
457
+ private hasSmartPricingStrategies;
424
458
  shouldRecalculateProductBookingPricesForContextChange(params: BaseSalesPriceRecalculationContextChange): boolean;
425
459
  calculateProductBookingPrices(paramsList: BaseSalesCalculateProductBookingPriceParams[]): Promise<BaseSalesProductBookingPriceResult[]>;
426
- addProductToOrder(product: Partial<BaseSalesOrderProduct> & BaseSalesOrderProductIdentity, booking?: AddProductBookingInput): Promise<import("../../modules/Order/types").OrderProduct[]>;
460
+ addProductToOrder(product: Partial<BaseSalesOrderProduct> & BaseSalesOrderProductIdentity, booking?: AddProductBookingInput, options?: AddProductToOrderOptions): Promise<import("../../modules/Order/types").OrderProduct[]>;
427
461
  updateOrderProduct(params: UpdateOrderProductParams): Promise<import("../../modules/Order/types").OrderProduct[]>;
428
462
  updateOrderProducts(paramsList: UpdateOrderProductParams[]): Promise<import("../../modules/Order/types").OrderProduct[]>;
429
463
  updateOrderProductQuantity(params: BaseSalesUpdateOrderProductQuantityParams): Promise<import("../../modules/Order/types").OrderProduct[]>;
@@ -439,8 +473,8 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
439
473
  * @example
440
474
  * await baseSales.removeProductsFromOrder([identityA, identityB]);
441
475
  */
442
- removeProductsFromOrder(identities: BaseSalesOrderProductIdentity[]): Promise<import("../../modules/Order/types").OrderProduct[]>;
443
- removeProductFromOrder(identity: BaseSalesOrderProductIdentity): Promise<import("../../modules/Order/types").OrderProduct[]>;
476
+ removeProductsFromOrder(identities: BaseSalesOrderProductIdentity[], options?: RemoveProductsFromOrderOptions): Promise<import("../../modules/Order/types").OrderProduct[]>;
477
+ removeProductFromOrder(identity: BaseSalesOrderProductIdentity, options?: RemoveProductsFromOrderOptions): Promise<import("../../modules/Order/types").OrderProduct[]>;
444
478
  /**
445
479
  * 注入促销评估器到底层 OrderModule。
446
480
  *
@@ -470,7 +504,7 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
470
504
  getUnfulfilledPromotions(): OrderUnfulfilledPromotion[];
471
505
  /** 最近一次促销计算输出的赠品操作 diff。 */
472
506
  getLastGiftActions(): OrderLastGiftActions | null;
473
- getProductList(): Promise<any>;
507
+ getProductList(): Promise<import("../..").ProductData[] | undefined>;
474
508
  getOtherParams(): Record<string, any>;
475
509
  setOtherParams(params: Record<string, any>, { cover }?: {
476
510
  cover?: boolean;