@pisell/pisellos 2.2.313 → 2.2.315

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 (215) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +3 -1
  3. package/dist/model/strategy/adapter/itemRule/adapter.d.ts +3 -1
  4. package/dist/model/strategy/adapter/itemRule/adapter.js +74 -7
  5. package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +3 -1
  6. package/dist/model/strategy/adapter/itemRule/evaluator.js +13 -0
  7. package/dist/model/strategy/adapter/itemRule/type.d.ts +40 -1
  8. package/dist/model/strategy/adapter/itemRule/type.js +10 -0
  9. package/dist/modules/BookingContext/utils/productExtend.d.ts +7 -0
  10. package/dist/modules/BookingContext/utils/productExtend.js +62 -18
  11. package/dist/modules/BookingContext/utils/resources.js +1 -1
  12. package/dist/modules/BusinessAvailability/index.d.ts +30 -0
  13. package/dist/modules/BusinessAvailability/index.js +204 -0
  14. package/dist/modules/Cart/index.js +4 -3
  15. package/dist/modules/Cart/types.d.ts +2 -0
  16. package/dist/modules/Cart/utils/cartProduct.d.ts +3 -1
  17. package/dist/modules/Cart/utils/cartProduct.js +59 -32
  18. package/dist/modules/FulfillmentTiming/index.d.ts +11 -0
  19. package/dist/modules/FulfillmentTiming/index.js +407 -0
  20. package/dist/modules/FulfillmentTiming/types.d.ts +67 -0
  21. package/dist/modules/FulfillmentTiming/types.js +1 -0
  22. package/dist/modules/OpenData/types.d.ts +14 -0
  23. package/dist/modules/Order/index.d.ts +14 -2
  24. package/dist/modules/Order/index.js +856 -486
  25. package/dist/modules/Order/localEftposState.d.ts +13 -0
  26. package/dist/modules/Order/localEftposState.js +39 -0
  27. package/dist/modules/Order/pickupTiming.d.ts +46 -0
  28. package/dist/modules/Order/pickupTiming.js +53 -0
  29. package/dist/modules/Order/types.d.ts +30 -2
  30. package/dist/modules/Order/utils.js +25 -7
  31. package/dist/modules/Payment/index.js +9 -10
  32. package/dist/modules/Product/types.d.ts +11 -0
  33. package/dist/modules/ProductList/index.js +1 -1
  34. package/dist/modules/ResourcePlanner/planner.d.ts +2 -0
  35. package/dist/modules/ResourcePlanner/planner.js +332 -23
  36. package/dist/modules/ResourcePlanner/types.d.ts +29 -0
  37. package/dist/modules/Schedule/index.d.ts +8 -0
  38. package/dist/modules/Schedule/index.js +141 -39
  39. package/dist/modules/index.d.ts +1 -0
  40. package/dist/modules/index.js +1 -0
  41. package/dist/plugins/request.d.ts +7 -0
  42. package/dist/server/index.d.ts +1 -0
  43. package/dist/server/index.js +1536 -1309
  44. package/dist/server/modules/form/index.d.ts +19 -0
  45. package/dist/server/modules/form/index.js +205 -0
  46. package/dist/server/modules/form/types.d.ts +13 -0
  47. package/dist/server/modules/form/types.js +3 -0
  48. package/dist/server/modules/index.d.ts +3 -0
  49. package/dist/server/modules/index.js +4 -0
  50. package/dist/server/modules/order/index.d.ts +15 -0
  51. package/dist/server/modules/order/index.js +920 -688
  52. package/dist/server/modules/order/types.d.ts +1 -0
  53. package/dist/server/test.json +1 -1
  54. package/dist/server/utils/small-ticket.d.ts +1 -85
  55. package/dist/server/utils/small-ticket.js +2 -2542
  56. package/dist/shared/payment/loadPaymentMethods.d.ts +9 -0
  57. package/dist/shared/payment/loadPaymentMethods.js +66 -0
  58. package/dist/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
  59. package/dist/shared/receipt/customerInvoiceLanguages.js +60 -0
  60. package/dist/shared/receipt/loadCustomerInvoiceLayout.d.ts +27 -0
  61. package/dist/shared/receipt/loadCustomerInvoiceLayout.js +184 -0
  62. package/dist/shared/receipt/small-ticket.d.ts +96 -0
  63. package/dist/shared/receipt/small-ticket.js +2751 -0
  64. package/dist/shared/receipt/templateVisibility.d.ts +23 -0
  65. package/dist/shared/receipt/templateVisibility.js +64 -0
  66. package/dist/shared/sales/loadSalesOrderSnapshot.d.ts +9 -0
  67. package/dist/shared/sales/loadSalesOrderSnapshot.js +21 -0
  68. package/dist/solution/BaseSales/fulfillmentItemRules.d.ts +27 -0
  69. package/dist/solution/BaseSales/fulfillmentItemRules.js +750 -0
  70. package/dist/solution/BaseSales/index.d.ts +39 -16
  71. package/dist/solution/BaseSales/index.js +1754 -1154
  72. package/dist/solution/BaseSales/pickupTiming.d.ts +47 -0
  73. package/dist/solution/BaseSales/pickupTiming.js +616 -0
  74. package/dist/solution/BaseSales/types.d.ts +11 -0
  75. package/dist/solution/BaseSales/utils/parseSalesResponse.js +3 -0
  76. package/dist/solution/BookingByStep/index.d.ts +4 -2
  77. package/dist/solution/BookingByStep/index.js +8 -3
  78. package/dist/solution/BookingTicket/index.d.ts +8 -2
  79. package/dist/solution/BookingTicket/index.js +513 -436
  80. package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
  81. package/dist/solution/BookingTicket/utils/addProductDecision.js +1 -1
  82. package/dist/solution/BookingTicket/utils/cartView.js +3 -1
  83. package/dist/solution/OrderInvoicePreview/index.d.ts +66 -0
  84. package/dist/solution/OrderInvoicePreview/index.js +340 -0
  85. package/dist/solution/RegisterAndLogin/config.js +54 -11
  86. package/dist/solution/RegisterAndLogin/index.d.ts +2 -0
  87. package/dist/solution/RegisterAndLogin/index.js +1 -1
  88. package/dist/solution/RegisterAndLogin/utils.d.ts +12 -4
  89. package/dist/solution/RegisterAndLogin/utils.js +36 -16
  90. package/dist/solution/Sales/index.js +1 -1
  91. package/dist/solution/UnifiedBookingSales/businessAvailability.d.ts +27 -0
  92. package/dist/solution/UnifiedBookingSales/businessAvailability.js +292 -0
  93. package/dist/solution/UnifiedBookingSales/index.d.ts +36 -4
  94. package/dist/solution/UnifiedBookingSales/index.js +1714 -905
  95. package/dist/solution/UnifiedBookingSales/types.d.ts +16 -2
  96. package/dist/solution/VenueBooking/index.d.ts +15 -2
  97. package/dist/solution/VenueBooking/index.js +1062 -785
  98. package/dist/solution/VenueBooking/types.d.ts +2 -1
  99. package/dist/solution/VenueBooking/types.js +1 -0
  100. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  101. package/dist/solution/VenueBooking/utils/dateSummary.js +7 -4
  102. package/dist/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
  103. package/dist/solution/VenueBooking/utils/smartPricing.js +273 -0
  104. package/dist/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
  105. package/dist/solution/VenueBooking/utils/timeSlot.js +6 -3
  106. package/dist/solution/index.d.ts +1 -0
  107. package/dist/solution/index.js +2 -1
  108. package/lib/index.d.ts +2 -0
  109. package/lib/index.js +21 -1
  110. package/lib/model/strategy/adapter/itemRule/adapter.d.ts +3 -1
  111. package/lib/model/strategy/adapter/itemRule/adapter.js +54 -4
  112. package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +3 -1
  113. package/lib/model/strategy/adapter/itemRule/evaluator.js +9 -0
  114. package/lib/model/strategy/adapter/itemRule/type.d.ts +40 -1
  115. package/lib/model/strategy/adapter/itemRule/type.js +10 -0
  116. package/lib/modules/BookingContext/utils/productExtend.d.ts +7 -0
  117. package/lib/modules/BookingContext/utils/productExtend.js +45 -2
  118. package/lib/modules/BookingContext/utils/resources.js +1 -1
  119. package/lib/modules/BusinessAvailability/index.d.ts +30 -0
  120. package/lib/modules/BusinessAvailability/index.js +146 -0
  121. package/lib/modules/Cart/index.js +4 -2
  122. package/lib/modules/Cart/types.d.ts +2 -0
  123. package/lib/modules/Cart/utils/cartProduct.d.ts +3 -1
  124. package/lib/modules/Cart/utils/cartProduct.js +39 -20
  125. package/lib/modules/FulfillmentTiming/index.d.ts +11 -0
  126. package/lib/modules/FulfillmentTiming/index.js +359 -0
  127. package/lib/modules/FulfillmentTiming/types.d.ts +67 -0
  128. package/lib/modules/FulfillmentTiming/types.js +5 -0
  129. package/lib/modules/OpenData/types.d.ts +14 -0
  130. package/lib/modules/Order/index.d.ts +14 -2
  131. package/lib/modules/Order/index.js +240 -38
  132. package/lib/modules/Order/localEftposState.d.ts +13 -0
  133. package/lib/modules/Order/localEftposState.js +44 -0
  134. package/lib/modules/Order/pickupTiming.d.ts +46 -0
  135. package/lib/modules/Order/pickupTiming.js +61 -0
  136. package/lib/modules/Order/types.d.ts +30 -2
  137. package/lib/modules/Order/utils.js +21 -5
  138. package/lib/modules/Payment/index.js +3 -4
  139. package/lib/modules/Product/types.d.ts +11 -0
  140. package/lib/modules/ProductList/index.js +1 -1
  141. package/lib/modules/ResourcePlanner/planner.d.ts +2 -0
  142. package/lib/modules/ResourcePlanner/planner.js +252 -8
  143. package/lib/modules/ResourcePlanner/types.d.ts +29 -0
  144. package/lib/modules/Schedule/index.d.ts +8 -0
  145. package/lib/modules/Schedule/index.js +68 -12
  146. package/lib/modules/index.d.ts +1 -0
  147. package/lib/modules/index.js +11 -0
  148. package/lib/plugins/request.d.ts +7 -0
  149. package/lib/server/index.d.ts +1 -0
  150. package/lib/server/index.js +158 -37
  151. package/lib/server/modules/form/index.d.ts +19 -0
  152. package/lib/server/modules/form/index.js +73 -0
  153. package/lib/server/modules/form/types.d.ts +13 -0
  154. package/lib/server/modules/form/types.js +9 -0
  155. package/lib/server/modules/index.d.ts +3 -0
  156. package/lib/server/modules/index.js +15 -1
  157. package/lib/server/modules/order/index.d.ts +15 -0
  158. package/lib/server/modules/order/index.js +114 -3
  159. package/lib/server/modules/order/types.d.ts +1 -0
  160. package/lib/server/test.json +1 -1
  161. package/lib/server/utils/small-ticket.d.ts +1 -85
  162. package/lib/server/utils/small-ticket.js +9 -2305
  163. package/lib/shared/payment/loadPaymentMethods.d.ts +9 -0
  164. package/lib/shared/payment/loadPaymentMethods.js +40 -0
  165. package/lib/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
  166. package/lib/shared/receipt/customerInvoiceLanguages.js +58 -0
  167. package/lib/shared/receipt/loadCustomerInvoiceLayout.d.ts +27 -0
  168. package/lib/shared/receipt/loadCustomerInvoiceLayout.js +124 -0
  169. package/lib/shared/receipt/small-ticket.d.ts +96 -0
  170. package/lib/shared/receipt/small-ticket.js +2546 -0
  171. package/lib/shared/receipt/templateVisibility.d.ts +23 -0
  172. package/lib/shared/receipt/templateVisibility.js +63 -0
  173. package/lib/shared/sales/loadSalesOrderSnapshot.d.ts +9 -0
  174. package/lib/shared/sales/loadSalesOrderSnapshot.js +22 -0
  175. package/lib/solution/BaseSales/fulfillmentItemRules.d.ts +27 -0
  176. package/lib/solution/BaseSales/fulfillmentItemRules.js +259 -0
  177. package/lib/solution/BaseSales/index.d.ts +39 -16
  178. package/lib/solution/BaseSales/index.js +333 -31
  179. package/lib/solution/BaseSales/pickupTiming.d.ts +47 -0
  180. package/lib/solution/BaseSales/pickupTiming.js +290 -0
  181. package/lib/solution/BaseSales/types.d.ts +11 -0
  182. package/lib/solution/BaseSales/utils/parseSalesResponse.js +3 -0
  183. package/lib/solution/BookingByStep/index.d.ts +4 -2
  184. package/lib/solution/BookingByStep/index.js +7 -3
  185. package/lib/solution/BookingTicket/index.d.ts +8 -2
  186. package/lib/solution/BookingTicket/index.js +65 -6
  187. package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
  188. package/lib/solution/BookingTicket/utils/addProductDecision.js +1 -1
  189. package/lib/solution/BookingTicket/utils/cartView.js +3 -1
  190. package/lib/solution/OrderInvoicePreview/index.d.ts +66 -0
  191. package/lib/solution/OrderInvoicePreview/index.js +246 -0
  192. package/lib/solution/RegisterAndLogin/config.js +57 -11
  193. package/lib/solution/RegisterAndLogin/index.d.ts +2 -0
  194. package/lib/solution/RegisterAndLogin/index.js +9 -1
  195. package/lib/solution/RegisterAndLogin/utils.d.ts +12 -4
  196. package/lib/solution/RegisterAndLogin/utils.js +24 -17
  197. package/lib/solution/Sales/index.js +1 -1
  198. package/lib/solution/UnifiedBookingSales/businessAvailability.d.ts +27 -0
  199. package/lib/solution/UnifiedBookingSales/businessAvailability.js +138 -0
  200. package/lib/solution/UnifiedBookingSales/index.d.ts +36 -4
  201. package/lib/solution/UnifiedBookingSales/index.js +561 -74
  202. package/lib/solution/UnifiedBookingSales/types.d.ts +16 -2
  203. package/lib/solution/VenueBooking/index.d.ts +15 -2
  204. package/lib/solution/VenueBooking/index.js +243 -96
  205. package/lib/solution/VenueBooking/types.d.ts +2 -1
  206. package/lib/solution/VenueBooking/types.js +1 -0
  207. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  208. package/lib/solution/VenueBooking/utils/dateSummary.js +7 -4
  209. package/lib/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
  210. package/lib/solution/VenueBooking/utils/smartPricing.js +224 -0
  211. package/lib/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
  212. package/lib/solution/VenueBooking/utils/timeSlot.js +5 -2
  213. package/lib/solution/index.d.ts +1 -0
  214. package/lib/solution/index.js +11 -0
  215. package/package.json +1 -1
@@ -8,6 +8,7 @@ var _exportNames = {
8
8
  };
9
9
  exports.BaseSalesImpl = void 0;
10
10
  var _BaseModule = require("../../modules/BaseModule");
11
+ var _localEftposState = require("../../modules/Order/localEftposState");
11
12
  var _types = require("./types");
12
13
  Object.keys(_types).forEach(function (key) {
13
14
  if (key === "default" || key === "__esModule") return;
@@ -21,6 +22,9 @@ Object.keys(_types).forEach(function (key) {
21
22
  });
22
23
  });
23
24
  var _Order = require("../../modules/Order");
25
+ var _pickupTiming = require("../../modules/Order/pickupTiming");
26
+ var _pickupTiming2 = require("./pickupTiming");
27
+ var _fulfillmentItemRules = require("./fulfillmentItemRules");
24
28
  var _decimal = _interopRequireDefault(require("decimal.js"));
25
29
  var _lodashEs = require("lodash-es");
26
30
  var _types2 = require("../BookingByStep/types");
@@ -499,6 +503,9 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
499
503
  serverOrderChangeHydrateInFlight = null;
500
504
  queuedServerOrderChanges = [];
501
505
  serverOrderChangeSyncEnabled = false;
506
+ pickupTimingEnabled = false;
507
+ pickupTimingController;
508
+ fulfillmentItemRulesController;
502
509
  constructor(name, version) {
503
510
  super(name, version);
504
511
  }
@@ -584,8 +591,12 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
584
591
  }
585
592
  this.queuedServerOrderChanges.push(snapshot);
586
593
  }
594
+ shouldSyncServerOrderChanges() {
595
+ const payments = this.store.order?.getTempOrder()?.payments || [];
596
+ return this.serverOrderChangeSyncEnabled || payments.some(_localEftposState.isLocalFinalizedPayment) && !payments.some(_paymentUtils.isPendingOrderPayment);
597
+ }
587
598
  async drainQueuedServerOrderChanges() {
588
- if (!this.serverOrderChangeSyncEnabled || this.salesDetailLoadInFlightCount > 0 || this.serverOrderChangeHydrateInFlight || this.queuedServerOrderChanges.length === 0) return;
599
+ if (!this.shouldSyncServerOrderChanges() || this.salesDetailLoadInFlightCount > 0 || this.serverOrderChangeHydrateInFlight || this.queuedServerOrderChanges.length === 0) return;
589
600
  const changedOrders = this.queuedServerOrderChanges;
590
601
  this.queuedServerOrderChanges = [];
591
602
  await this.syncCurrentSalesDetailFromServerOrderChange({
@@ -593,8 +604,9 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
593
604
  });
594
605
  }
595
606
  async syncCurrentSalesDetailFromServerOrderChange(payload) {
596
- const changedOrders = Array.isArray(payload) ? payload : Array.isArray(payload?.changedOrders) ? payload.changedOrders : payload?.data && typeof payload.data === 'object' ? [payload.data] : [];
597
- if (!this.serverOrderChangeSyncEnabled) return;
607
+ const fullSnapshotAfterFinalization = Array.isArray(payload?.list) && this.store.order?.getTempOrder()?.payments?.some(_localEftposState.isLocalFinalizedPayment);
608
+ const changedOrders = Array.isArray(payload) ? payload : Array.isArray(payload?.changedOrders) && payload.changedOrders.length > 0 ? payload.changedOrders : fullSnapshotAfterFinalization ? payload.list : payload?.data && typeof payload.data === 'object' ? [payload.data] : [];
609
+ if (!this.shouldSyncServerOrderChanges()) return;
598
610
 
599
611
  // 显式详情加载期间 current 可能仍是上一单,先按订单身份 latest-only 缓存;
600
612
  // load 完成后再用新的 current 过滤,避免恰好到达的最新支付快照丢失。
@@ -1037,7 +1049,30 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1037
1049
  customerId: params.customerId,
1038
1050
  channel: params.channel
1039
1051
  });
1040
- return productIds.map(productId => productId === null ? null : productsById.get(productId) || null);
1052
+ const shouldAlignSelectedVariantPrice = handledByOsServer && this.preferAuthoritativeProductQueryPrice();
1053
+ return productIds.map((productId, index) => {
1054
+ const authoritativeProduct = productId === null ? null : productsById.get(productId) || null;
1055
+ if (!shouldAlignSelectedVariantPrice || !authoritativeProduct) return authoritativeProduct;
1056
+ const selectedProduct = selectedProducts[index];
1057
+ const selectedVariantId = this.getSelectedProductVariantId(selectedProduct);
1058
+ if (!selectedVariantId || this.getSelectedProductVariantId(authoritativeProduct) === selectedVariantId) {
1059
+ return authoritativeProduct;
1060
+ }
1061
+
1062
+ // OS 返回的是目录商品;已命中的智能价格不能被规格基础价覆盖。
1063
+ const appliedFields = authoritativeProduct._dataVariant?.appliedFields;
1064
+ if (Array.isArray(appliedFields) && ['price', 'selling_price', 'original_price', 'base_price'].some(field => appliedFields.includes(field))) {
1065
+ return authoritativeProduct;
1066
+ }
1067
+ const selectedVariant = Array.isArray(authoritativeProduct.variant) ? authoritativeProduct.variant.find(variant => Number(variant?.id) === selectedVariantId) : undefined;
1068
+ const selectedPrice = [selectedVariant?.price, selectedVariant?.selling_price, selectedVariant?.base_price, params.priceQueries[index].fallback_price, selectedProduct.price, selectedProduct.selling_price, selectedProduct.original_price].find(value => (typeof value === 'number' || typeof value === 'string' && value.trim() !== '') && Number.isFinite(Number(value)));
1069
+
1070
+ // 每行独立保留所选规格价格(含 0 元),避免同商品多规格共用目录对象串价。
1071
+ return selectedPrice === undefined ? authoritativeProduct : {
1072
+ ...authoritativeProduct,
1073
+ price: selectedPrice
1074
+ };
1075
+ });
1041
1076
  }
1042
1077
  const queryPayload = this.buildPriceQueryPayload({
1043
1078
  ids,
@@ -1157,6 +1192,98 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1157
1192
  return this.otherParams?.channel;
1158
1193
  }
1159
1194
 
1195
+ /** Only solutions opting into Pickup Timing supply effective OpenData. */
1196
+ async loadPickupTimingOpenData(_force) {
1197
+ return {};
1198
+ }
1199
+ async loadFulfillmentItemRuleOpenData() {
1200
+ const openData = this.otherParams?.openData ?? this.otherParams?.dineInConfig;
1201
+ return openData && typeof openData === 'object' && !Array.isArray(openData) ? openData : null;
1202
+ }
1203
+ getFulfillmentItemRulesController() {
1204
+ if (!this.fulfillmentItemRulesController) {
1205
+ this.fulfillmentItemRulesController = new _fulfillmentItemRules.FulfillmentItemRulesController({
1206
+ getOrder: () => {
1207
+ if (!this.store.order) throw new Error('order 模块未初始化');
1208
+ return this.store.order;
1209
+ },
1210
+ getProducts: () => this.store.products,
1211
+ loadOpenData: () => this.loadFulfillmentItemRuleOpenData(),
1212
+ getScope: () => this.getPickupTimingScope(),
1213
+ getOtherParams: () => this.otherParams,
1214
+ fetchStrategyModels: ids => this.request.get('/promotion', {
1215
+ skip: 1,
1216
+ num: 99,
1217
+ status: 'active',
1218
+ ids
1219
+ }),
1220
+ reportError: error => this.logWarning('履约费用策略执行失败,保留服务类型设置', {
1221
+ error: error instanceof Error ? error.message : String(error)
1222
+ })
1223
+ });
1224
+ }
1225
+ return this.fulfillmentItemRulesController;
1226
+ }
1227
+ isPickupTimingEnabled() {
1228
+ return this.pickupTimingEnabled && this.otherParams?.enablePickupTiming !== false;
1229
+ }
1230
+ getPickupTimingContextData(key) {
1231
+ const context = this.core?.context;
1232
+ const getData = context?.getData;
1233
+ return typeof getData === 'function' ? getData.call(context, key) : undefined;
1234
+ }
1235
+ getPickupTimingScope() {
1236
+ return JSON.stringify({
1237
+ shop: this.getPickupTimingContextData('shop_id'),
1238
+ businessCode: this.otherParams?.businessCode ?? this.otherParams?.business_code,
1239
+ channel: this.getSubmitOrderSalesChannel(),
1240
+ timezone: this.getPickupTimingContextData('timezone'),
1241
+ platform: (0, _platform.normalizeRuntimePlatform)(this.otherParams?.platform),
1242
+ cacheId: this.cacheId
1243
+ });
1244
+ }
1245
+ resetPickupTimingCache() {
1246
+ this.pickupTimingController?.invalidate();
1247
+ }
1248
+ getPickupTimingController() {
1249
+ if (!this.pickupTimingController) {
1250
+ this.pickupTimingController = new _pickupTiming2.PickupTimingController({
1251
+ getOrder: () => {
1252
+ if (!this.store.order) throw new Error('order 模块未初始化');
1253
+ return this.store.order;
1254
+ },
1255
+ setServiceType: serviceType => this.setServiceType(serviceType),
1256
+ getSchedule: () => this.store.schedule,
1257
+ loadOpenData: force => this.loadPickupTimingOpenData(force),
1258
+ getTimezone: () => String(this.getPickupTimingContextData('timezone') ?? ''),
1259
+ getScope: () => this.getPickupTimingScope(),
1260
+ isPos: () => (0, _platform.normalizeRuntimePlatform)(this.otherParams?.platform) === 'pos'
1261
+ });
1262
+ }
1263
+ return this.pickupTimingController;
1264
+ }
1265
+ getPickupTimingAvailability(params) {
1266
+ return this.getPickupTimingController().getAvailability(params);
1267
+ }
1268
+ getPickupTimingSelection() {
1269
+ return this.getPickupTimingController().getSelection();
1270
+ }
1271
+ setPickupTimingSelection(selection) {
1272
+ return this.getPickupTimingController().setSelection(selection);
1273
+ }
1274
+ validatePickupTimingSelection(selection) {
1275
+ return this.getPickupTimingController().validate(selection);
1276
+ }
1277
+ preparePickupTimingForCheckout(options) {
1278
+ if (!this.isPickupTimingEnabled()) {
1279
+ return Promise.resolve({
1280
+ serviceType: String(this.getTempOrder()?.metadata?.shop_service_data?.service_type || ''),
1281
+ mode: 'asap'
1282
+ });
1283
+ }
1284
+ return this.getPickupTimingController().prepare(options);
1285
+ }
1286
+
1160
1287
  /** Subclasses with target-scoped OpenData override this guard before reusing the cache. */
1161
1288
  isInvoiceOpenDataCacheCurrent() {
1162
1289
  return true;
@@ -1438,6 +1565,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1438
1565
  return isChanged;
1439
1566
  }
1440
1567
  async initialize(core, options = {}) {
1568
+ this.resetPickupTimingCache();
1441
1569
  this.core = core;
1442
1570
  this.initializeOptions = options || {};
1443
1571
  this.paymentNumberDevicePrefix = null;
@@ -1490,6 +1618,8 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1490
1618
  this.core.effects.emit(`${this.name}:onInited`, {});
1491
1619
  }
1492
1620
  async destroy() {
1621
+ this.resetPickupTimingCache();
1622
+ this.fulfillmentItemRulesController?.invalidate();
1493
1623
  this.serverOrderChangeUnsubscribe?.();
1494
1624
  this.serverOrderChangeUnsubscribe = null;
1495
1625
  this.paymentMethodsChangedUnsubscribe?.();
@@ -1589,9 +1719,12 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1589
1719
  /** 获取根 booking(is_next === 0 / is_root === 1),多个时取第一个。 */
1590
1720
  getRootBooking() {
1591
1721
  if (!this.currentSalesDetail) return null;
1592
- if (this.currentSalesDetail.rootBooking) return this.currentSalesDetail.rootBooking;
1722
+ if (this.currentSalesDetail.rootBooking && !(0, _pickupTiming.isFulfillmentTimingBooking)(this.currentSalesDetail.rootBooking)) {
1723
+ return this.currentSalesDetail.rootBooking;
1724
+ }
1593
1725
  const bookings = this.currentSalesDetail.bookings || [];
1594
1726
  return bookings.find(booking => {
1727
+ if ((0, _pickupTiming.isFulfillmentTimingBooking)(booking)) return false;
1595
1728
  const parentId = booking?.parent_id;
1596
1729
  return parentId === 0 || parentId === null || parentId === undefined;
1597
1730
  }) || null;
@@ -1704,9 +1837,26 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1704
1837
  if (!this.store.order) throw new Error('order 模块未初始化');
1705
1838
  return this.store.order.updateTempOrderPickupReferenceMode(mode);
1706
1839
  }
1707
- setServiceType(serviceType) {
1840
+ async setServiceType(serviceType) {
1708
1841
  if (!this.store.order) throw new Error('order 模块未初始化');
1709
- return this.store.order.updateTempOrderServiceType(serviceType);
1842
+ const serviceData = this.store.order.updateTempOrderServiceType(serviceType);
1843
+ await this.getFulfillmentItemRulesController().apply(serviceType);
1844
+ // 费用规则可能增删商品;即使没有普通促销,也要同步页面的购物车和金额快照。
1845
+ const tempOrder = this.getTempOrder();
1846
+ if (tempOrder) await this.effectsEmit('onTempOrderReplaced', {
1847
+ tempOrder
1848
+ });
1849
+ return serviceData;
1850
+ }
1851
+ getPickupTimingBooking() {
1852
+ return this.store.order?.getPickupTimingBooking() || null;
1853
+ }
1854
+ setPickupTimingBooking(input) {
1855
+ if (!this.store.order) throw new Error('order 模块未初始化');
1856
+ return this.store.order.setPickupTimingBooking(input);
1857
+ }
1858
+ clearPickupTimingBooking() {
1859
+ this.store.order?.clearPickupTimingBooking();
1710
1860
  }
1711
1861
  updateTempOrderContactsInfo(contactsInfo) {
1712
1862
  if (!this.store.order) throw new Error('order 模块未初始化');
@@ -1788,6 +1938,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1788
1938
  async clearOrderCartLines() {
1789
1939
  try {
1790
1940
  if (!this.store.order) throw new Error('order 模块未初始化');
1941
+ this.fulfillmentItemRulesController?.invalidate();
1791
1942
  const tempOrder = await this.store.order.clearOrderCartLines();
1792
1943
  if (this.currentSalesDetail) {
1793
1944
  this.currentSalesDetail = {
@@ -1815,6 +1966,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
1815
1966
  /** 切换法币 / WalletPass 单位时清空商品、折扣与支付状态,保留客户。 */
1816
1967
  async clearOrderForSettlementSwitch() {
1817
1968
  if (!this.store.order) throw new Error('order 模块未初始化');
1969
+ this.fulfillmentItemRulesController?.invalidate();
1818
1970
  const tempOrder = await this.store.order.clearOrderForSettlementSwitch();
1819
1971
  if (this.currentSalesDetail) {
1820
1972
  this.currentSalesDetail = {
@@ -2402,7 +2554,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2402
2554
  // Deprecated compatibility alias. New BaseSales callers should use submitSalesOrder.
2403
2555
  return this.submitSalesOrder(params);
2404
2556
  }
2405
- async buildVirtualSettlementSubmitData() {
2557
+ buildVirtualSettlementOrderData() {
2406
2558
  if (!this.store.order) return null;
2407
2559
  const tempOrder = this.store.order.getTempOrder();
2408
2560
  if (!this.isActiveVirtualSettlementOrder(tempOrder)) return null;
@@ -2411,6 +2563,21 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2411
2563
  if (!snapshot || !Number.isFinite(currencyProductId) || currencyProductId <= 0) {
2412
2564
  throw new Error('Virtual currency settlement configuration is invalid.');
2413
2565
  }
2566
+ return {
2567
+ snapshot,
2568
+ currencyProductId,
2569
+ currencyCode: String(tempOrder?.currency_code || ''),
2570
+ currencySymbol: String(tempOrder?.currency_symbol || ''),
2571
+ currencyFormat: String(tempOrder?.currency_format || 'symbol_first')
2572
+ };
2573
+ }
2574
+ async buildVirtualSettlementSubmitData() {
2575
+ const settlement = this.buildVirtualSettlementOrderData();
2576
+ if (!settlement || !this.store.order) return null;
2577
+ const tempOrder = this.store.order.getTempOrder();
2578
+ const {
2579
+ currencyProductId
2580
+ } = settlement;
2414
2581
  const summary = await this.store.order.recalculateSummary({
2415
2582
  createIfMissing: true
2416
2583
  });
@@ -2425,17 +2592,10 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2425
2592
  });
2426
2593
  }
2427
2594
  const asset = this.store.order.getVirtualCurrencyList().find(item => Number(item?.product_id) === currencyProductId);
2428
- const currencyCode = String(tempOrder?.currency_code || '');
2429
- const currencySymbol = String(tempOrder?.currency_symbol || '');
2430
- const currencyFormat = String(tempOrder?.currency_format || 'symbol_first');
2431
2595
  if (amount.lte(0)) {
2432
2596
  return {
2433
- payments: [],
2434
- snapshot,
2435
- currencyProductId,
2436
- currencyCode,
2437
- currencySymbol,
2438
- currencyFormat
2597
+ ...settlement,
2598
+ payments: []
2439
2599
  };
2440
2600
  }
2441
2601
  if (!asset) {
@@ -2489,12 +2649,8 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2489
2649
  };
2490
2650
  }
2491
2651
  return {
2492
- payments: [payment],
2493
- snapshot,
2494
- currencyProductId,
2495
- currencyCode,
2496
- currencySymbol,
2497
- currencyFormat
2652
+ ...settlement,
2653
+ payments: [payment]
2498
2654
  };
2499
2655
  }
2500
2656
 
@@ -2508,11 +2664,48 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2508
2664
  if (!this.store.order) {
2509
2665
  throw new Error('BaseSales 解决方案需要 order 模块支持');
2510
2666
  }
2511
- const virtualSettlement = await this.buildVirtualSettlementSubmitData();
2667
+ if (this.isPickupTimingEnabled()) await this.preparePickupTimingForCheckout({
2668
+ freeze: true
2669
+ });
2670
+ const isDeferredPayment = params?.paymentExecution === 'deferred';
2671
+ const virtualPaymentSettlement = isDeferredPayment ? null : await this.buildVirtualSettlementSubmitData();
2672
+ const virtualSettlement = isDeferredPayment ? this.buildVirtualSettlementOrderData() : virtualPaymentSettlement;
2512
2673
  // this.store.order.persistTempOrder();
2513
- const inferredPaymentStatus = this.getSubmitPaymentStatus(params?.paymentStatus);
2674
+ const inferredPaymentStatus = isDeferredPayment ? undefined : this.getSubmitPaymentStatus(params?.paymentStatus);
2514
2675
  const smallTicketDataFlag = params?.smallTicketDataFlag ?? this.getDefaultCheckoutSmallTicketDataFlag();
2515
- const enhancePayload = this.buildSubmitPayloadEnhancerWithOpenDataConfig(params?.enhancePayload);
2676
+ const virtualSettlementEnhancePayload = virtualSettlement ? (payload, ctx) => {
2677
+ const callerPayload = params?.enhancePayload ? params.enhancePayload(payload, ctx) : payload;
2678
+ const currencySettlementConfig = callerPayload.metadata?.currency_settlement_config || {};
2679
+ return {
2680
+ ...callerPayload,
2681
+ metadata: {
2682
+ ...(callerPayload.metadata || {}),
2683
+ currency_settlement_config: {
2684
+ ...currencySettlementConfig,
2685
+ settlement_type: 'virtual_currency',
2686
+ settlement_ids: [virtualSettlement.currencyProductId],
2687
+ currency_display_snapshot: (0, _lodashEs.cloneDeep)(currencySettlementConfig.currency_display_snapshot ?? (0, _virtualSettlement.buildCurrencyDisplaySnapshot)(virtualSettlement.snapshot))
2688
+ }
2689
+ },
2690
+ currency_code: virtualSettlement.currencyCode,
2691
+ currency_symbol: virtualSettlement.currencySymbol,
2692
+ currency_format: virtualSettlement.currencyFormat
2693
+ };
2694
+ } : params?.enhancePayload;
2695
+ const configuredEnhancePayload = this.buildSubmitPayloadEnhancerWithOpenDataConfig(virtualSettlementEnhancePayload);
2696
+ // Apply this last so neither a stale draft status nor a caller enhancer can
2697
+ // turn deferred submission into payment. The live wallet selection is untouched.
2698
+ const enhancePayload = isDeferredPayment ? (payload, ctx) => {
2699
+ const enhancedPayload = configuredEnhancePayload ? configuredEnhancePayload(payload, ctx) : payload;
2700
+ const {
2701
+ payment_status: _paymentStatus,
2702
+ ...orderPayload
2703
+ } = enhancedPayload;
2704
+ return {
2705
+ ...orderPayload,
2706
+ payments: []
2707
+ };
2708
+ } : configuredEnhancePayload;
2516
2709
  const submitParams = {
2517
2710
  cacheId: this.cacheId,
2518
2711
  platform: this.otherParams?.platform,
@@ -2520,8 +2713,10 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2520
2713
  channel: this.getSubmitOrderSalesChannel(),
2521
2714
  type: this.otherParams?.type,
2522
2715
  request_unique_idempotency_token: this.store.order.generateIdempotencyToken(),
2523
- ...(virtualSettlement ? {
2524
- payments: virtualSettlement.payments
2716
+ ...(isDeferredPayment ? {
2717
+ payments: []
2718
+ } : virtualPaymentSettlement ? {
2719
+ payments: virtualPaymentSettlement.payments
2525
2720
  } : params?.payments !== undefined ? {
2526
2721
  payments: params.payments
2527
2722
  } : {}),
@@ -2531,7 +2726,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2531
2726
  ...(smallTicketDataFlag !== undefined ? {
2532
2727
  smallTicketDataFlag
2533
2728
  } : {}),
2534
- ...(virtualSettlement ? {
2729
+ ...(isDeferredPayment || virtualSettlement ? {
2535
2730
  confirmPendingVoucherPayments: false
2536
2731
  } : params?.confirmPendingVoucherPayments !== undefined ? {
2537
2732
  confirmPendingVoucherPayments: params.confirmPendingVoucherPayments
@@ -2562,10 +2757,109 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2562
2757
  };
2563
2758
  return this.shouldUseCheckoutSyncTask() ? this.store.order.submitTempOrder(submitParams) : this.store.order.submitTempOrderAsync(submitParams);
2564
2759
  }
2760
+ pendingLocalEftposFinalizations = new Map();
2761
+ async finalizeLocalEftposPayment(params) {
2762
+ const key = `${params.saleId}:${params.paymentNumber}`;
2763
+ // If SQLite rejects the write, retry this known result before another payment can start.
2764
+ this.pendingLocalEftposFinalizations.set(key, params);
2765
+ const response = await this.request.post('/local/finalizeLocalEftposPayment', {
2766
+ sale_id: params.saleId,
2767
+ payment_number: params.paymentNumber,
2768
+ result: params.result,
2769
+ failed_transaction_numbers: params.failedTransactionNumbers
2770
+ }, {
2771
+ osServer: true,
2772
+ customToast: () => {}
2773
+ });
2774
+ if (response?.code !== 200 || !response?.data?.order) {
2775
+ throw new Error(response?.message || '本地支付收尾失败,请刷新订单后重试');
2776
+ }
2777
+ this.pendingLocalEftposFinalizations.delete(key);
2778
+ const {
2779
+ order,
2780
+ payment
2781
+ } = response.data;
2782
+ const temp = this.getTempOrder();
2783
+ const isCurrentOrder = String(temp?.external_sale_number || temp?.order_id) === String(params.saleId) || temp?.order_id && String(temp.order_id) === String(order.order_id);
2784
+ if (isCurrentOrder) {
2785
+ // Persisted by the local route already. Saving a draft here would re-enable protection.
2786
+ if (temp?.payments?.some(item => String(item.payment_number) === params.paymentNumber)) {
2787
+ await this.updateOrderPayment(params.paymentNumber, payment, {
2788
+ persistDraft: false,
2789
+ submitWhenPaid: false
2790
+ });
2791
+ }
2792
+ if ((0, _localEftposState.requiresLocalPaymentRefresh)(order)) {
2793
+ // Set the in-memory gate before the GET so a failed refresh also blocks this page.
2794
+ const currentTemp = this.getTempOrder();
2795
+ if (currentTemp) currentTemp.metadata = {
2796
+ ...currentTemp.metadata,
2797
+ ...order.metadata
2798
+ };
2799
+ try {
2800
+ await this.loadSalesDetail({
2801
+ orderId: order.order_id,
2802
+ forceRemote: true,
2803
+ merge: false
2804
+ });
2805
+ } catch {
2806
+ throw new Error(_localEftposState.PAYMENT_REFRESH_MESSAGE);
2807
+ }
2808
+ }
2809
+ } else if ((0, _localEftposState.requiresLocalPaymentRefresh)(order)) {
2810
+ const refreshed = await this.store.order?.getSalesOrderByLookup({
2811
+ lookup: order.order_id,
2812
+ forceRemote: true
2813
+ });
2814
+ if (refreshed?.code !== 200) throw new Error(_localEftposState.PAYMENT_REFRESH_MESSAGE);
2815
+ }
2816
+ return response.data;
2817
+ }
2818
+
2819
+ /** Entry gate also reads SQLite state, so stale sessions/restarts cannot bypass it. */
2820
+ async ensureSalesOrderReadyForPayment() {
2821
+ const temp = this.getTempOrder();
2822
+ const unfinished = [...this.pendingLocalEftposFinalizations.values()].filter(params => String(params.saleId) === String(temp?.external_sale_number) || String(params.saleId) === String(temp?.order_id));
2823
+ if (unfinished.length > 0) {
2824
+ for (const params of unfinished) await this.finalizeLocalEftposPayment(params);
2825
+ throw new Error('订单已更新,请确认商品和金额后重新付款');
2826
+ }
2827
+ const lookup = temp?.order_id || temp?.external_sale_number;
2828
+ let localOrder = null;
2829
+ if (lookup && this.core?.server?.hasRoute?.('post', '/shop/local/orderPaymentReadiness')) {
2830
+ const response = await this.request.post('/local/orderPaymentReadiness', {
2831
+ sale_id: lookup
2832
+ }, {
2833
+ osServer: true,
2834
+ customToast: () => {}
2835
+ });
2836
+ if (response?.code !== 200) throw new Error(_localEftposState.PAYMENT_REFRESH_MESSAGE);
2837
+ localOrder = response.data;
2838
+ }
2839
+ if (!(0, _localEftposState.requiresLocalPaymentRefresh)(temp) && !(0, _localEftposState.requiresLocalPaymentRefresh)(localOrder)) return;
2840
+ const orderId = localOrder?.order_id || temp?.order_id;
2841
+ if (!orderId || String(orderId) === String(temp?.external_sale_number)) {
2842
+ throw new Error(_localEftposState.PAYMENT_REFRESH_MESSAGE);
2843
+ }
2844
+ try {
2845
+ await this.loadSalesDetail({
2846
+ orderId,
2847
+ forceRemote: true,
2848
+ merge: false
2849
+ });
2850
+ } catch {
2851
+ throw new Error(_localEftposState.PAYMENT_REFRESH_MESSAGE);
2852
+ }
2853
+ // The initiating UI may have captured the old amount before this await.
2854
+ throw new Error('订单已刷新,请确认商品和金额后重新付款');
2855
+ }
2565
2856
  async saveSalesOrderDraft(params) {
2566
2857
  if (!this.store.order) {
2567
2858
  throw new Error('BaseSales 解决方案需要 order 模块支持');
2568
2859
  }
2860
+ if (this.isPickupTimingEnabled()) await this.preparePickupTimingForCheckout({
2861
+ freeze: false
2862
+ });
2569
2863
  return this.store.order.saveTempOrderAsDraft({
2570
2864
  cacheId: this.cacheId,
2571
2865
  platform: params?.platform ?? this.otherParams?.platform,
@@ -2581,6 +2875,9 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
2581
2875
  if (!this.store.order) {
2582
2876
  throw new Error('BaseSales 解决方案需要 order 模块支持');
2583
2877
  }
2878
+ if (this.isPickupTimingEnabled()) await this.preparePickupTimingForCheckout({
2879
+ freeze: true
2880
+ });
2584
2881
  const inferredPaymentStatus = this.getSubmitPaymentStatus(params?.paymentStatus);
2585
2882
  const smallTicketDataFlag = params?.smallTicketDataFlag ?? this.getDefaultCheckoutSmallTicketDataFlag();
2586
2883
  const enhancePayload = this.buildSubmitPayloadEnhancerWithOpenDataConfig(params?.enhancePayload);
@@ -3508,6 +3805,9 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
3508
3805
  if (!Number.isFinite(actualPaidAmount) || actualPaidAmount + 0.01 < amount) {
3509
3806
  throw new Error('顾客实收现金不能小于支付金额');
3510
3807
  }
3808
+ if (this.isPickupTimingEnabled()) await this.preparePickupTimingForCheckout({
3809
+ freeze: true
3810
+ });
3511
3811
  this.window?.interaction?.utils?.postMessageToApp?.({
3512
3812
  module: 'till',
3513
3813
  key: 'open_till',
@@ -3887,7 +4187,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
3887
4187
  async addProductToOrder(product, booking, options) {
3888
4188
  try {
3889
4189
  if (!this.store.order) throw new Error('order 模块未初始化');
3890
- const products = await this.store.order.addProductToOrder(product, booking, options);
4190
+ const products = options === undefined ? await this.store.order.addProductToOrder(product, booking) : await this.store.order.addProductToOrder(product, booking, options);
3891
4191
  // // 需要叠加
3892
4192
  // if (this.hooks.onAddProductOverlay) {
3893
4193
  // const res = this.hooks.onAddProductOverlay(是否叠加, product)
@@ -3976,7 +4276,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
3976
4276
  async removeProductsFromOrder(identities, options) {
3977
4277
  try {
3978
4278
  if (!this.store.order) throw new Error('order 模块未初始化');
3979
- return await this.store.order.removeProductsFromOrder(identities, options);
4279
+ return options === undefined ? await this.store.order.removeProductsFromOrder(identities) : await this.store.order.removeProductsFromOrder(identities, options);
3980
4280
  } catch (error) {
3981
4281
  throw error;
3982
4282
  }
@@ -4061,6 +4361,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
4061
4361
  async setOtherParams(params, {
4062
4362
  cover = false
4063
4363
  } = {}) {
4364
+ const previousPickupTimingScope = this.getPickupTimingScope();
4064
4365
  if (cover) {
4065
4366
  this.otherParams = {
4066
4367
  ...params
@@ -4072,6 +4373,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
4072
4373
  };
4073
4374
  }
4074
4375
  this.cacheId = this.otherParams?.cacheId;
4376
+ if (previousPickupTimingScope !== this.getPickupTimingScope()) this.resetPickupTimingCache();
4075
4377
  await this.syncOtherParamsToSubModules(params, {
4076
4378
  cover
4077
4379
  });
@@ -0,0 +1,47 @@
1
+ import type { OrderModule } from '../../modules/Order';
2
+ import type { ShopServiceType } from '../../modules/Order/types';
3
+ import type { ScheduleModule } from '../../modules/Schedule';
4
+ import { type PickupTimingAvailability, type PickupTimingSelection, type PickupTimingValidationResult } from '../../modules/FulfillmentTiming';
5
+ interface PickupTimingHost {
6
+ getOrder: () => OrderModule;
7
+ setServiceType?: (serviceType: ShopServiceType) => unknown | Promise<unknown>;
8
+ getSchedule: () => ScheduleModule | undefined;
9
+ loadOpenData: (force: boolean) => Promise<Record<string, unknown>>;
10
+ getTimezone: () => string;
11
+ getScope: () => string;
12
+ isPos: () => boolean;
13
+ now?: () => Date;
14
+ }
15
+ /** Reuses runtime configuration and schedules; every calculation still uses the live clock. */
16
+ export declare class PickupTimingController {
17
+ private readonly host;
18
+ private latest?;
19
+ private runtime?;
20
+ private writeSequence;
21
+ constructor(host: PickupTimingHost);
22
+ private now;
23
+ /** A new solution context or an explicit settings refresh invalidates pending work too. */
24
+ invalidate(): void;
25
+ private assertCurrentRuntime;
26
+ private getRuntime;
27
+ private loadConfig;
28
+ private loadSchedules;
29
+ /** Preserve an existing POS choice without adding it to the shared settings cache. */
30
+ private getEffectiveConfig;
31
+ private snapshot;
32
+ getAvailability(params?: {
33
+ date?: string;
34
+ force?: boolean;
35
+ }): Promise<PickupTimingAvailability>;
36
+ getSelection(): PickupTimingSelection;
37
+ private validateSnapshot;
38
+ validate(selection: PickupTimingSelection): Promise<PickupTimingValidationResult>;
39
+ setSelection(selection: PickupTimingSelection, options?: {
40
+ frozen?: boolean;
41
+ }): Promise<PickupTimingSelection>;
42
+ /** Called before a new checkout/payment; payment callbacks keep their already prepared appointment. */
43
+ prepare(options?: {
44
+ freeze?: boolean;
45
+ }): Promise<PickupTimingSelection>;
46
+ }
47
+ export {};