@pisell/pisellos 0.10.8 → 0.10.10

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 (129) 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 +7 -3
  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/OpenData/types.d.ts +1 -0
  18. package/dist/modules/Order/index.d.ts +20 -1
  19. package/dist/modules/Order/index.js +976 -730
  20. package/dist/modules/Order/types.d.ts +6 -1
  21. package/dist/modules/Order/utils/virtualSettlement.d.ts +56 -0
  22. package/dist/modules/Order/utils/virtualSettlement.js +271 -0
  23. package/dist/modules/Order/utils.js +89 -48
  24. package/dist/modules/Payment/types.d.ts +2 -0
  25. package/dist/modules/Payment/utils.js +4 -1
  26. package/dist/modules/Payment/walletpass.d.ts +11 -0
  27. package/dist/modules/Payment/walletpass.js +235 -60
  28. package/dist/modules/Product/types.d.ts +23 -0
  29. package/dist/modules/ProductList/index.d.ts +15 -2
  30. package/dist/modules/ProductList/index.js +92 -13
  31. package/dist/modules/ResourcePlanner/index.d.ts +0 -22
  32. package/dist/modules/ResourcePlanner/index.js +1 -180
  33. package/dist/modules/ResourcePlanner/localClock.d.ts +33 -0
  34. package/dist/modules/ResourcePlanner/localClock.js +183 -0
  35. package/dist/modules/ResourcePlanner/planner.d.ts +5 -14
  36. package/dist/modules/ResourcePlanner/planner.js +2019 -936
  37. package/dist/modules/ResourcePlanner/types.d.ts +346 -187
  38. package/dist/modules/ResourcePlanner/types.js +33 -1
  39. package/dist/modules/SalesSummary/index.d.ts +1 -0
  40. package/dist/modules/SalesSummary/index.js +4 -3
  41. package/dist/modules/SalesSummary/types.d.ts +1 -0
  42. package/dist/modules/SalesSummary/utils.d.ts +1 -0
  43. package/dist/modules/SalesSummary/utils.js +21 -1
  44. package/dist/server/index.d.ts +9 -0
  45. package/dist/server/index.js +90 -58
  46. package/dist/server/modules/order/index.d.ts +1 -0
  47. package/dist/server/modules/order/index.js +252 -94
  48. package/dist/server/utils/small-ticket.js +2 -1
  49. package/dist/solution/BaseSales/index.d.ts +26 -2
  50. package/dist/solution/BaseSales/index.js +1310 -931
  51. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  52. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +78 -12
  53. package/dist/solution/BookingByStep/index.d.ts +4 -4
  54. package/dist/solution/BookingTicket/index.d.ts +5 -1
  55. package/dist/solution/BookingTicket/index.js +225 -161
  56. package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +2 -1
  57. package/dist/solution/BookingTicket/utils/addProductDecision.js +5 -3
  58. package/dist/solution/ScanOrder/index.js +25 -64
  59. package/dist/solution/UnifiedBookingSales/index.d.ts +110 -73
  60. package/dist/solution/UnifiedBookingSales/index.js +3349 -971
  61. package/dist/solution/UnifiedBookingSales/remoteOccupancyCache.d.ts +49 -0
  62. package/dist/solution/UnifiedBookingSales/remoteOccupancyCache.js +430 -0
  63. package/dist/solution/UnifiedBookingSales/types.d.ts +133 -76
  64. package/dist/solution/UnifiedBookingSales/types.js +4 -9
  65. package/lib/core/index.js +0 -1
  66. package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
  67. package/lib/model/strategy/adapter/dataVariant/evaluator.js +170 -7
  68. package/lib/model/strategy/adapter/dataVariant/type.d.ts +25 -0
  69. package/lib/model/strategy/adapter/walletPass/evaluator.js +0 -2
  70. package/lib/model/strategy/adapter/walletPass/type.d.ts +5 -0
  71. package/lib/model/strategy/adapter/walletPass/utils.js +62 -11
  72. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +3 -0
  73. package/lib/modules/BookingContext/utils/productExtend.js +4 -3
  74. package/lib/modules/BookingContext/utils/timeSlices.js +18 -3
  75. package/lib/modules/Customer/index.d.ts +4 -0
  76. package/lib/modules/Customer/index.js +11 -0
  77. package/lib/modules/Customer/types.d.ts +2 -0
  78. package/lib/modules/Discount/index.d.ts +2 -0
  79. package/lib/modules/Discount/index.js +37 -3
  80. package/lib/modules/Discount/types.d.ts +11 -0
  81. package/lib/modules/OpenData/types.d.ts +1 -0
  82. package/lib/modules/Order/index.d.ts +20 -1
  83. package/lib/modules/Order/index.js +393 -128
  84. package/lib/modules/Order/types.d.ts +6 -1
  85. package/lib/modules/Order/utils/virtualSettlement.d.ts +56 -0
  86. package/lib/modules/Order/utils/virtualSettlement.js +300 -0
  87. package/lib/modules/Order/utils.js +65 -21
  88. package/lib/modules/Payment/types.d.ts +2 -0
  89. package/lib/modules/Payment/utils.js +5 -1
  90. package/lib/modules/Payment/walletpass.d.ts +11 -0
  91. package/lib/modules/Payment/walletpass.js +198 -17
  92. package/lib/modules/Product/types.d.ts +23 -0
  93. package/lib/modules/ProductList/index.d.ts +15 -2
  94. package/lib/modules/ProductList/index.js +85 -3
  95. package/lib/modules/ResourcePlanner/index.d.ts +0 -22
  96. package/lib/modules/ResourcePlanner/index.js +0 -123
  97. package/lib/modules/ResourcePlanner/localClock.d.ts +33 -0
  98. package/lib/modules/ResourcePlanner/localClock.js +270 -0
  99. package/lib/modules/ResourcePlanner/planner.d.ts +5 -14
  100. package/lib/modules/ResourcePlanner/planner.js +1903 -798
  101. package/lib/modules/ResourcePlanner/types.d.ts +346 -187
  102. package/lib/modules/ResourcePlanner/types.js +19 -0
  103. package/lib/modules/SalesSummary/index.d.ts +1 -0
  104. package/lib/modules/SalesSummary/index.js +10 -2
  105. package/lib/modules/SalesSummary/types.d.ts +1 -0
  106. package/lib/modules/SalesSummary/utils.d.ts +1 -0
  107. package/lib/modules/SalesSummary/utils.js +25 -1
  108. package/lib/server/index.d.ts +9 -0
  109. package/lib/server/index.js +54 -14
  110. package/lib/server/modules/order/index.d.ts +1 -0
  111. package/lib/server/modules/order/index.js +66 -2
  112. package/lib/server/utils/small-ticket.js +1 -1
  113. package/lib/solution/BaseSales/index.d.ts +26 -2
  114. package/lib/solution/BaseSales/index.js +261 -23
  115. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  116. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +61 -11
  117. package/lib/solution/BookingByStep/index.d.ts +4 -4
  118. package/lib/solution/BookingTicket/index.d.ts +5 -1
  119. package/lib/solution/BookingTicket/index.js +32 -3
  120. package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +2 -1
  121. package/lib/solution/BookingTicket/utils/addProductDecision.js +4 -1
  122. package/lib/solution/ScanOrder/index.js +17 -54
  123. package/lib/solution/UnifiedBookingSales/index.d.ts +110 -73
  124. package/lib/solution/UnifiedBookingSales/index.js +2289 -374
  125. package/lib/solution/UnifiedBookingSales/remoteOccupancyCache.d.ts +49 -0
  126. package/lib/solution/UnifiedBookingSales/remoteOccupancyCache.js +376 -0
  127. package/lib/solution/UnifiedBookingSales/types.d.ts +133 -76
  128. package/lib/solution/UnifiedBookingSales/types.js +3 -2
  129. package/package.json +1 -1
@@ -890,13 +890,37 @@ function calculateSalesSummary(params) {
890
890
  surchargeList,
891
891
  scheduleById = {},
892
892
  isInScheduleByDate,
893
- shopDiscount
893
+ shopDiscount,
894
+ virtualSettlementMode = false
894
895
  } = params;
895
896
  if (!(products == null ? void 0 : products.length))
896
897
  return createEmptySalesSummary();
897
898
  const summaryProducts = products.filter((product) => !isGeneratedVoucherProduct(product));
898
899
  if (!summaryProducts.length)
899
900
  return createEmptySalesSummary();
901
+ if (virtualSettlementMode) {
902
+ const productQuantity2 = summaryProducts.reduce(
903
+ (sum, item) => sum + getSafeNum(item.num),
904
+ 0
905
+ );
906
+ const productAmount2 = summaryProducts.reduce(
907
+ (sum, item) => sum.plus(
908
+ toDecimal(item.selling_price).times(getSafeNum(item.num))
909
+ ),
910
+ new import_decimal.default(0)
911
+ );
912
+ const amount = toFixed2(productAmount2);
913
+ return {
914
+ ...createEmptySalesSummary(),
915
+ product_quantity: productQuantity2,
916
+ product_original_amount: amount,
917
+ product_amount: amount,
918
+ product_expect_amount: amount,
919
+ expect_amount: amount,
920
+ total_amount: amount,
921
+ is_price_include_tax: isPriceIncludeTax
922
+ };
923
+ }
900
924
  const productQuantity = summaryProducts.reduce(
901
925
  (sum, item) => sum + getSafeNum(item.num),
902
926
  0
@@ -263,6 +263,11 @@ declare class Server {
263
263
  * 对单个商品 query 订阅者重算并推送(定时路径;不新建 schedule timer)。
264
264
  */
265
265
  private recomputeAndNotifySubscriber;
266
+ /**
267
+ * 根据餐牌 ID 获取其绑定日程中的全部时间点。
268
+ * 商品查询定时器与 schedule-time-points 路由共用此逻辑。
269
+ */
270
+ private getMenuScheduleTimePoints;
266
271
  /**
267
272
  * query 完成后为 subscriber 同步 schedule 定时器(先 clear 再 schedule)。
268
273
  */
@@ -518,6 +523,10 @@ declare class Server {
518
523
  private handleOrderDraftSubmit;
519
524
  private handlePendingSyncCheckoutOrder;
520
525
  private buildPendingSyncCheckoutOrder;
526
+ /**
527
+ * Android 结账自动小票由当前设备设置控制;其它平台保持原有行为。
528
+ */
529
+ private shouldAutoPrintCheckoutReceipt;
521
530
  private shouldBuildSmallTicketData;
522
531
  private shouldPrintSyncedOrder;
523
532
  private hasPaymentStatus;
@@ -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,
@@ -2319,16 +2327,44 @@ var Server = class {
2319
2327
  });
2320
2328
  }
2321
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
+ }
2322
2347
  /**
2323
2348
  * query 完成后为 subscriber 同步 schedule 定时器(先 clear 再 schedule)。
2324
2349
  */
2325
- syncProductQueryScheduleTimers(subscriberId, strategy_context) {
2350
+ syncProductQueryScheduleTimers({
2351
+ subscriberId,
2352
+ menu_list_ids,
2353
+ strategy_context
2354
+ }) {
2326
2355
  var _a, _b;
2327
2356
  this.clearSubscriberScheduleTimers(subscriberId);
2328
2357
  if (!this.shouldScheduleProductQueryReload(strategy_context)) {
2329
2358
  return;
2330
2359
  }
2331
- 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
+ );
2332
2368
  if (timePoints.length > 0) {
2333
2369
  this.scheduleSubscriberTimePointReloads(subscriberId, timePoints);
2334
2370
  }
@@ -3791,7 +3827,6 @@ var Server = class {
3791
3827
  });
3792
3828
  }
3793
3829
  async handleOrderCheckoutSubmit(params) {
3794
- var _a;
3795
3830
  const { backendPath, data, title } = params;
3796
3831
  this.logInfo(`${title}: 开始处理`, {
3797
3832
  backendPath,
@@ -3816,10 +3851,7 @@ var Server = class {
3816
3851
  });
3817
3852
  if ((pendingResult == null ? void 0 : pendingResult.status) === true) {
3818
3853
  const pendingOrder = pendingResult.data;
3819
- const platform = (_a = this.core.context) == null ? void 0 : _a.getPlatform();
3820
- const isAndroid = platform === "android";
3821
- if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData) && this.isSalesOrderFullyPaid(pendingOrder) && // TODO 这里先加个兼容,如果是安卓,则需要 type=virtual 才走打印,如果是苹果则无限制
3822
- (isAndroid ? checkoutData.type === "virtual" : true)) {
3854
+ if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData) && this.isSalesOrderFullyPaid(pendingOrder) && this.shouldAutoPrintCheckoutReceipt()) {
3823
3855
  await this.dispatchLocalReceiptPrint({
3824
3856
  checkoutData,
3825
3857
  order: pendingOrder,
@@ -3882,9 +3914,8 @@ var Server = class {
3882
3914
  checkoutData: syncResult.checkoutData,
3883
3915
  order: syncedOrder,
3884
3916
  response: syncResult.normalizedResponse,
3885
- requireFullyPaid: true,
3917
+ requireFullyPaid: true
3886
3918
  // print_all 的 type=0 是收据打印;不要沿用同步成功后的券/手环打印 type=99。
3887
- isManualPrint: true
3888
3919
  });
3889
3920
  }
3890
3921
  return response;
@@ -4054,6 +4085,15 @@ var Server = class {
4054
4085
  { requireFullyPaid: true, productMap }
4055
4086
  );
4056
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
+ }
4057
4097
  shouldBuildSmallTicketData(order) {
4058
4098
  if (!order || typeof order !== "object")
4059
4099
  return false;
@@ -274,6 +274,7 @@ export declare class OrderModule extends BaseModule implements Module {
274
274
  * // => 'S-1001'
275
275
  */
276
276
  private getOrderStorageKey;
277
+ private getPersistedOrderStorageKey;
277
278
  private getOrderIdentityMatchKeys;
278
279
  private doOrdersShareIdentity;
279
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;
@@ -1533,6 +1534,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1533
1534
  const patchedOrders = [];
1534
1535
  const remoteProductMembershipChanges = [];
1535
1536
  const forceWriteStorageKeys = /* @__PURE__ */ new Set();
1537
+ const storageKeyMigrations = [];
1536
1538
  const mergeActions = {};
1537
1539
  const existingProductsHaveStableIdentity = this.store.list.map(
1538
1540
  (order) => this.doProductsHaveStableMembershipIdentity(
@@ -1557,6 +1559,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1557
1559
  const mergeKey = storageKey || (fresh.order_id !== void 0 && fresh.order_id !== null ? this.getIdKey(fresh.order_id) : "");
1558
1560
  if (matchIndex >= 0) {
1559
1561
  const existingOrder = updatedList[matchIndex];
1562
+ const previousStorageKey = this.getPersistedOrderStorageKey(existingOrder);
1560
1563
  if (this.isPendingSyncOrder(existingOrder) && this.isRemoteEchoMergeSource(source)) {
1561
1564
  this.logInfo("mergeOrdersToStore-跳过 pending 订单远端覆盖", {
1562
1565
  source,
@@ -1618,6 +1621,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1618
1621
  }
1619
1622
  }
1620
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
+ }
1621
1632
  updatedList[adjustedMatchIndex] = mergedOrder;
1622
1633
  existingProductsHaveStableIdentity[adjustedMatchIndex] = mergedProductsHaveStableIdentity;
1623
1634
  if (membershipChange) {
@@ -1655,7 +1666,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1655
1666
  patchedOrders,
1656
1667
  source,
1657
1668
  mergeActions,
1658
- {},
1669
+ { storageKeyMigrations },
1659
1670
  forceWriteStorageKeys
1660
1671
  );
1661
1672
  this.logInfo("mergeOrdersToStore-结束", {
@@ -1860,6 +1871,13 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1860
1871
  }
1861
1872
  return "";
1862
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
+ }
1863
1881
  getOrderIdentityMatchKeys(order) {
1864
1882
  return this.getOrderIdentityEntries(order).map((entry) => `${entry.field}:${entry.key}`);
1865
1883
  }
@@ -2290,7 +2308,18 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2290
2308
  throw new Error("订单 SQLite 数据库未初始化");
2291
2309
  return;
2292
2310
  }
2293
- 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));
2294
2323
  if (ordersSnapshot.length === 0) {
2295
2324
  return;
2296
2325
  }
@@ -2307,6 +2336,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2307
2336
  if (compactedToWrite.length === 0) {
2308
2337
  return;
2309
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
+ }
2310
2350
  try {
2311
2351
  await this.runInOrderSQLiteSaveQueue(async () => {
2312
2352
  let writeMethod = "none";
@@ -2330,6 +2370,30 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2330
2370
  throw new Error("订单 SQLite 数据库不支持写入");
2331
2371
  }
2332
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
+ }
2333
2397
  this.logInfo("patchOrdersInSQLite-完成", {
2334
2398
  source,
2335
2399
  count: compactedToWrite.length,
@@ -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);
@@ -4,7 +4,7 @@ import { BaseSalesOrderProduct, BaseSalesOrderProductIdentity, BaseSalesPaymentS
4
4
  import { OrderModule } from '../../modules/Order';
5
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';
@@ -119,6 +119,15 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
119
119
  * application_code 仅作为接口兼容字段,不能替代 channel / business_code。
120
120
  */
121
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;
122
131
  private getPriceQuerySchedule;
123
132
  private loadProductsForPriceQuery;
124
133
  private loadProductForPriceQuery;
@@ -166,6 +175,9 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
166
175
  protected setPaymentNumberDevicePrefix(prefix: unknown): void;
167
176
  private getPaymentNumberDevicePrefixSync;
168
177
  private getPaymentNumberDevicePrefixAsync;
178
+ private isMultiCurrencySettlementEnabled;
179
+ private isActiveVirtualSettlementOrder;
180
+ private isHistoricalVirtualSettlementOrder;
169
181
  private syncAppDataToTempOrder;
170
182
  initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
171
183
  destroy(): Promise<void>;
@@ -218,6 +230,8 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
218
230
  * 同步清空内存中的 salesDetail 商品/预约视图,避免编辑态仍读到旧 bookings。
219
231
  */
220
232
  clearOrderCartLines(): Promise<OrderTempOrder>;
233
+ /** 切换法币 / WalletPass 单位时清空商品、折扣与支付状态,保留客户。 */
234
+ clearOrderForSettlementSwitch(): Promise<OrderTempOrder>;
221
235
  getOrderProducts(): import("../../modules/Order/types").OrderProduct[];
222
236
  getSummary(): Promise<OrderSummary>;
223
237
  private getHistoricalProductDiscountList;
@@ -228,12 +242,15 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
228
242
  loadDiscountConfig(params?: {
229
243
  customerId?: number;
230
244
  action?: 'create' | 'edit';
245
+ force?: boolean;
231
246
  }): Promise<{
232
247
  productList: Record<string, any>[];
233
248
  discountList: Discount[];
234
249
  availableWalletIds: number[];
250
+ virtualCurrencyList: VirtualCurrencyAsset[];
235
251
  }>;
236
252
  getAvailableWalletIds(): number[];
253
+ getVirtualCurrencyList(): VirtualCurrencyAsset[];
237
254
  bestDiscount(cb?: (result: any) => void): Promise<{
238
255
  productList: Record<string, any>[];
239
256
  discountList: Discount[];
@@ -265,6 +282,7 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
265
282
  confirmPendingVoucherPayments?: boolean;
266
283
  enhancePayload?: SubmitPayloadEnhancer;
267
284
  }): Promise<T>;
285
+ private buildVirtualSettlementSubmitData;
268
286
  /**
269
287
  * 提交当前 Sales 订单。
270
288
  *
@@ -364,6 +382,11 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
364
382
  selected: boolean;
365
383
  source?: WalletAssetSelectionSource;
366
384
  }): Promise<WalletAssetsState>;
385
+ /** 更新已选钱包资产的手动使用金额,并同步 pending payment。 */
386
+ updateWalletAssetAmount(params: {
387
+ assetId: WalletAssetId;
388
+ amount: number;
389
+ }): Promise<WalletAssetsState>;
367
390
  /** 扫码精确查券;仅可用资产会被自动选中。 */
368
391
  scanWalletAsset(code: string): Promise<ScanWalletAssetResult>;
369
392
  /** 清空全部未确认钱包选择,已支付钱包项由 Order 模块继续保留。 */
@@ -431,6 +454,7 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
431
454
  transformBaseProductToOrderProduct(params: TransformBaseProductToOrderProductParams): import("./utils/transformBaseProductToOrderProduct").BaseProductOrderProductInput | null;
432
455
  calculateProductBookingPrice(params: BaseSalesCalculateProductBookingPriceParams): Promise<BaseSalesProductBookingPriceResult>;
433
456
  getQuotationCustomerScopeInfo(): BaseSalesQuotationCustomerScopeInfo;
457
+ private hasSmartPricingStrategies;
434
458
  shouldRecalculateProductBookingPricesForContextChange(params: BaseSalesPriceRecalculationContextChange): boolean;
435
459
  calculateProductBookingPrices(paramsList: BaseSalesCalculateProductBookingPriceParams[]): Promise<BaseSalesProductBookingPriceResult[]>;
436
460
  addProductToOrder(product: Partial<BaseSalesOrderProduct> & BaseSalesOrderProductIdentity, booking?: AddProductBookingInput, options?: AddProductToOrderOptions): Promise<import("../../modules/Order/types").OrderProduct[]>;
@@ -480,7 +504,7 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
480
504
  getUnfulfilledPromotions(): OrderUnfulfilledPromotion[];
481
505
  /** 最近一次促销计算输出的赠品操作 diff。 */
482
506
  getLastGiftActions(): OrderLastGiftActions | null;
483
- getProductList(): Promise<any>;
507
+ getProductList(): Promise<import("../..").ProductData[] | undefined>;
484
508
  getOtherParams(): Record<string, any>;
485
509
  setOtherParams(params: Record<string, any>, { cover }?: {
486
510
  cover?: boolean;