@pisell/pisellos 2.3.49 → 2.3.51

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 (144) hide show
  1. package/dist/modules/Discount/index.d.ts +1 -0
  2. package/dist/modules/Discount/index.js +40 -11
  3. package/dist/modules/Discount/types.d.ts +1 -0
  4. package/dist/modules/Holder/index.d.ts +48 -0
  5. package/dist/modules/Holder/index.js +640 -0
  6. package/dist/modules/Holder/types.d.ts +123 -0
  7. package/dist/modules/Holder/types.js +1 -0
  8. package/dist/modules/Holder/utils.d.ts +13 -0
  9. package/dist/modules/Holder/utils.js +34 -0
  10. package/dist/modules/OpenData/index.js +2 -2
  11. package/dist/modules/Order/index.d.ts +4 -2
  12. package/dist/modules/Order/index.js +54 -25
  13. package/dist/modules/Order/types.d.ts +9 -0
  14. package/dist/modules/Order/utils.d.ts +10 -0
  15. package/dist/modules/Order/utils.js +35 -3
  16. package/dist/modules/Product/types.d.ts +1 -0
  17. package/dist/modules/ProductList/index.js +33 -14
  18. package/dist/modules/Quotation/index.d.ts +1 -1
  19. package/dist/modules/Quotation/index.js +2 -2
  20. package/dist/modules/ResourcePlanner/index.d.ts +24 -0
  21. package/dist/modules/ResourcePlanner/index.js +181 -0
  22. package/dist/modules/ResourcePlanner/planner.d.ts +14 -0
  23. package/dist/modules/ResourcePlanner/planner.js +1069 -0
  24. package/dist/modules/ResourcePlanner/types.d.ts +227 -0
  25. package/dist/modules/ResourcePlanner/types.js +1 -0
  26. package/dist/modules/Rules/index.js +47 -13
  27. package/dist/modules/SalesSummary/index.js +12 -13
  28. package/dist/modules/ScanOrderLogger/index.d.ts +2 -0
  29. package/dist/modules/ScanOrderLogger/index.js +15 -2
  30. package/dist/modules/ScanOrderLogger/providers/feishu.js +45 -27
  31. package/dist/modules/ScanOrderLogger/types.d.ts +1 -0
  32. package/dist/modules/Schedule/index.d.ts +3 -1
  33. package/dist/modules/Schedule/index.js +21 -16
  34. package/dist/modules/Summary/utils.js +38 -13
  35. package/dist/modules/index.d.ts +2 -0
  36. package/dist/modules/index.js +3 -1
  37. package/dist/plugins/window.d.ts +1 -0
  38. package/dist/server/index.d.ts +14 -0
  39. package/dist/server/index.js +907 -793
  40. package/dist/solution/BaseSales/index.d.ts +7 -0
  41. package/dist/solution/BaseSales/index.js +64 -42
  42. package/dist/solution/BookingByStep/index.d.ts +17 -2
  43. package/dist/solution/BookingByStep/index.js +294 -215
  44. package/dist/solution/BookingByStep/types.d.ts +2 -1
  45. package/dist/solution/BookingByStep/types.js +3 -1
  46. package/dist/solution/BookingByStep/utils/capacity.js +17 -1
  47. package/dist/solution/BookingByStep/utils/timeslots.d.ts +3 -1
  48. package/dist/solution/BookingByStep/utils/timeslots.js +19 -12
  49. package/dist/solution/BookingTicket/index.js +2 -2
  50. package/dist/solution/BookingTicket/utils/scan/handleScan.d.ts +3 -1
  51. package/dist/solution/BookingTicket/utils/scan/handleScan.js +10 -2
  52. package/dist/solution/ScanOrder/index.d.ts +26 -14
  53. package/dist/solution/ScanOrder/index.js +1142 -739
  54. package/dist/solution/ScanOrder/types.d.ts +21 -1
  55. package/dist/solution/ScanOrder/utils.d.ts +8 -0
  56. package/dist/solution/ScanOrder/utils.js +66 -25
  57. package/dist/solution/ShopDiscount/index.d.ts +1 -0
  58. package/dist/solution/ShopDiscount/index.js +125 -87
  59. package/dist/solution/UnifiedBookingSales/index.d.ts +183 -0
  60. package/dist/solution/UnifiedBookingSales/index.js +1891 -0
  61. package/dist/solution/UnifiedBookingSales/types.d.ts +143 -0
  62. package/dist/solution/UnifiedBookingSales/types.js +11 -0
  63. package/dist/solution/VenueBooking/index.d.ts +39 -11
  64. package/dist/solution/VenueBooking/index.js +1167 -841
  65. package/dist/solution/VenueBooking/types.d.ts +3 -0
  66. package/dist/solution/VenueBooking/utils/resource.js +1 -0
  67. package/dist/solution/VenueBooking/utils/slotMerge.d.ts +4 -4
  68. package/dist/solution/VenueBooking/utils/slotMerge.js +10 -5
  69. package/dist/solution/index.d.ts +1 -0
  70. package/dist/solution/index.js +2 -1
  71. package/dist/types/index.d.ts +1 -0
  72. package/lib/model/strategy/adapter/promotion/index.js +51 -0
  73. package/lib/modules/Discount/index.d.ts +1 -0
  74. package/lib/modules/Discount/index.js +9 -0
  75. package/lib/modules/Discount/types.d.ts +1 -0
  76. package/lib/modules/Holder/index.d.ts +48 -0
  77. package/lib/modules/Holder/index.js +402 -0
  78. package/lib/modules/Holder/types.d.ts +123 -0
  79. package/lib/modules/Holder/types.js +17 -0
  80. package/lib/modules/Holder/utils.d.ts +13 -0
  81. package/lib/modules/Holder/utils.js +71 -0
  82. package/lib/modules/OpenData/index.js +1 -1
  83. package/lib/modules/Order/index.d.ts +4 -2
  84. package/lib/modules/Order/index.js +26 -10
  85. package/lib/modules/Order/types.d.ts +9 -0
  86. package/lib/modules/Order/utils.d.ts +10 -0
  87. package/lib/modules/Order/utils.js +36 -5
  88. package/lib/modules/Product/types.d.ts +1 -0
  89. package/lib/modules/ProductList/index.js +40 -31
  90. package/lib/modules/Quotation/index.d.ts +1 -1
  91. package/lib/modules/Quotation/index.js +2 -2
  92. package/lib/modules/ResourcePlanner/index.d.ts +24 -0
  93. package/lib/modules/ResourcePlanner/index.js +148 -0
  94. package/lib/modules/ResourcePlanner/planner.d.ts +14 -0
  95. package/lib/modules/ResourcePlanner/planner.js +933 -0
  96. package/lib/modules/ResourcePlanner/types.d.ts +227 -0
  97. package/lib/modules/ResourcePlanner/types.js +17 -0
  98. package/lib/modules/Rules/index.js +33 -16
  99. package/lib/modules/SalesSummary/index.js +6 -7
  100. package/lib/modules/ScanOrderLogger/index.d.ts +2 -0
  101. package/lib/modules/ScanOrderLogger/index.js +13 -1
  102. package/lib/modules/ScanOrderLogger/providers/feishu.js +15 -6
  103. package/lib/modules/ScanOrderLogger/types.d.ts +1 -0
  104. package/lib/modules/Schedule/index.d.ts +3 -1
  105. package/lib/modules/Schedule/index.js +10 -8
  106. package/lib/modules/Summary/utils.js +21 -1
  107. package/lib/modules/index.d.ts +2 -0
  108. package/lib/modules/index.js +5 -1
  109. package/lib/plugins/window.d.ts +1 -0
  110. package/lib/server/index.d.ts +14 -0
  111. package/lib/server/index.js +72 -15
  112. package/lib/solution/BaseSales/index.d.ts +7 -0
  113. package/lib/solution/BaseSales/index.js +24 -8
  114. package/lib/solution/BookingByStep/index.d.ts +17 -2
  115. package/lib/solution/BookingByStep/index.js +60 -18
  116. package/lib/solution/BookingByStep/types.d.ts +2 -1
  117. package/lib/solution/BookingByStep/types.js +5 -0
  118. package/lib/solution/BookingByStep/utils/capacity.js +20 -1
  119. package/lib/solution/BookingByStep/utils/timeslots.d.ts +3 -1
  120. package/lib/solution/BookingByStep/utils/timeslots.js +19 -11
  121. package/lib/solution/BookingTicket/index.js +10 -2
  122. package/lib/solution/BookingTicket/utils/scan/handleScan.d.ts +3 -1
  123. package/lib/solution/BookingTicket/utils/scan/handleScan.js +2 -2
  124. package/lib/solution/ScanOrder/index.d.ts +26 -14
  125. package/lib/solution/ScanOrder/index.js +449 -182
  126. package/lib/solution/ScanOrder/types.d.ts +21 -1
  127. package/lib/solution/ScanOrder/utils.d.ts +8 -0
  128. package/lib/solution/ScanOrder/utils.js +31 -0
  129. package/lib/solution/ShopDiscount/index.d.ts +1 -0
  130. package/lib/solution/ShopDiscount/index.js +14 -0
  131. package/lib/solution/UnifiedBookingSales/index.d.ts +183 -0
  132. package/lib/solution/UnifiedBookingSales/index.js +1084 -0
  133. package/lib/solution/UnifiedBookingSales/types.d.ts +143 -0
  134. package/lib/solution/UnifiedBookingSales/types.js +33 -0
  135. package/lib/solution/VenueBooking/index.d.ts +39 -11
  136. package/lib/solution/VenueBooking/index.js +322 -110
  137. package/lib/solution/VenueBooking/types.d.ts +3 -0
  138. package/lib/solution/VenueBooking/utils/resource.js +1 -0
  139. package/lib/solution/VenueBooking/utils/slotMerge.d.ts +4 -4
  140. package/lib/solution/VenueBooking/utils/slotMerge.js +6 -4
  141. package/lib/solution/index.d.ts +1 -0
  142. package/lib/solution/index.js +3 -1
  143. package/lib/types/index.d.ts +1 -0
  144. package/package.json +1 -1
@@ -49,6 +49,10 @@ declare class Server {
49
49
  private productQuerySubscribers;
50
50
  /** subscriberId → 智能定价变价时间点定时器句柄(与 subscriber 分离存储,便于 clear) */
51
51
  private productQueryScheduleTimers;
52
+ /** 餐牌筛选为空时才触发的菜单/日程缓存自愈,避免每次商品查询都请求远端。 */
53
+ private menuScheduleRefreshInFlight;
54
+ private lastMenuScheduleRefreshAt;
55
+ private readonly MENU_SCHEDULE_REFRESH_COOLDOWN_MS;
52
56
  private orderQuerySubscribers;
53
57
  private bookingQuerySubscribers;
54
58
  private bookingRemoteQuerySubscribers;
@@ -262,6 +266,16 @@ declare class Server {
262
266
  * 存储订阅者信息,便于数据变更时推送最新结果
263
267
  */
264
268
  private handleProductQuery;
269
+ /**
270
+ * ProductList callers such as standalone retail pages do not always have a selected schedule.
271
+ * In that case query against the current local time so menu availability can still be evaluated.
272
+ */
273
+ private resolveProductQueryScheduleContext;
274
+ /**
275
+ * OpenData 的关联餐牌可能已更新,而 server_menu/server_schedule 仍命中本地持久化缓存。
276
+ * 仅在当前筛选没有任何生效餐牌时刷新一次,并由调用方重新计算筛选结果。
277
+ */
278
+ private refreshMenuScheduleCacheAfterEmptyResult;
265
279
  /**
266
280
  * 按商品 id 查询单条(GET /shop/product/query/:productId)
267
281
  * schedule_date 必填:query 或 data;schedule_datetime 可选。不走订阅。
@@ -82,6 +82,10 @@ var Server = class {
82
82
  this.productQuerySubscribers = /* @__PURE__ */ new Map();
83
83
  /** subscriberId → 智能定价变价时间点定时器句柄(与 subscriber 分离存储,便于 clear) */
84
84
  this.productQueryScheduleTimers = /* @__PURE__ */ new Map();
85
+ /** 餐牌筛选为空时才触发的菜单/日程缓存自愈,避免每次商品查询都请求远端。 */
86
+ this.menuScheduleRefreshInFlight = null;
87
+ this.lastMenuScheduleRefreshAt = 0;
88
+ this.MENU_SCHEDULE_REFRESH_COOLDOWN_MS = 30 * 1e3;
85
89
  // ---- 订单 / 预约列表查询订阅者 ----
86
90
  this.orderQuerySubscribers = /* @__PURE__ */ new Map();
87
91
  this.bookingQuerySubscribers = /* @__PURE__ */ new Map();
@@ -215,7 +219,11 @@ var Server = class {
215
219
  */
216
220
  this.handleProductQuery = async ({ url, method, data, config }) => {
217
221
  console.log("[Server] handleProductQuery:", url, method, data, config);
218
- const { menu_list_ids, schedule_datetime, schedule_date, customer_id, ids, extension_type, strategy_context } = data;
222
+ const { menu_list_ids, customer_id, ids, extension_type, strategy_context } = data;
223
+ const { schedule_date, schedule_datetime } = this.resolveProductQueryScheduleContext({
224
+ schedule_date: data.schedule_date,
225
+ schedule_datetime: data.schedule_datetime
226
+ });
219
227
  const { callback, subscriberId } = config || {};
220
228
  this.logInfo("handleProductQuery: 开始处理商品查询请求", {
221
229
  menu_list_ids,
@@ -2211,15 +2219,12 @@ var Server = class {
2211
2219
  return;
2212
2220
  const scheduleDate = subscriber.context.schedule_date || (0, import_dayjs.default)().format("YYYY-MM-DD");
2213
2221
  const timerIds = [];
2214
- for (const timePoint of timePoints) {
2215
- const delayMs = this.computeScheduleTimePointDelayMs(scheduleDate, timePoint);
2216
- if (delayMs < 0)
2217
- continue;
2218
- const timerId = setTimeout(() => {
2219
- void this.onScheduleTimePointTimerFire(subscriberId, timerId);
2220
- }, delayMs);
2221
- timerIds.push(timerId);
2222
- }
2222
+ setInterval(() => {
2223
+ const currentTime = (0, import_dayjs.default)().format("hh:mm");
2224
+ if (timePoints.includes(currentTime)) {
2225
+ this.onScheduleTimePointTimerFire(subscriberId);
2226
+ }
2227
+ }, 6e4);
2223
2228
  if (timerIds.length > 0) {
2224
2229
  this.productQueryScheduleTimers.set(subscriberId, timerIds);
2225
2230
  subscriber.scheduleTimerIds = timerIds;
@@ -2234,7 +2239,7 @@ var Server = class {
2234
2239
  * schedule 变价时间点定时器触发:刷新 schedule_datetime 后重算并 callback。
2235
2240
  */
2236
2241
  async onScheduleTimePointTimerFire(subscriberId, timerId) {
2237
- this.removeScheduleTimerRef(subscriberId, timerId);
2242
+ timerId && this.removeScheduleTimerRef(subscriberId, timerId);
2238
2243
  if (!this.productQuerySubscribers.has(subscriberId))
2239
2244
  return;
2240
2245
  const subscriber = this.productQuerySubscribers.get(subscriberId);
@@ -2277,6 +2282,43 @@ var Server = class {
2277
2282
  this.scheduleSubscriberTimePointReloads(subscriberId, timePoints);
2278
2283
  }
2279
2284
  }
2285
+ /**
2286
+ * ProductList callers such as standalone retail pages do not always have a selected schedule.
2287
+ * In that case query against the current local time so menu availability can still be evaluated.
2288
+ */
2289
+ resolveProductQueryScheduleContext(params) {
2290
+ const now = (0, import_dayjs.default)();
2291
+ const schedule_datetime = typeof params.schedule_datetime === "string" && params.schedule_datetime.trim() ? params.schedule_datetime : now.format("YYYY-MM-DD HH:mm:ss");
2292
+ const schedule_date = typeof params.schedule_date === "string" && params.schedule_date.trim() ? params.schedule_date : (0, import_dayjs.default)(schedule_datetime).isValid() ? (0, import_dayjs.default)(schedule_datetime).format("YYYY-MM-DD") : now.format("YYYY-MM-DD");
2293
+ return { schedule_date, schedule_datetime };
2294
+ }
2295
+ /**
2296
+ * OpenData 的关联餐牌可能已更新,而 server_menu/server_schedule 仍命中本地持久化缓存。
2297
+ * 仅在当前筛选没有任何生效餐牌时刷新一次,并由调用方重新计算筛选结果。
2298
+ */
2299
+ async refreshMenuScheduleCacheAfterEmptyResult() {
2300
+ if (!this.menu || !this.schedule)
2301
+ return false;
2302
+ const now = Date.now();
2303
+ if (now - this.lastMenuScheduleRefreshAt < this.MENU_SCHEDULE_REFRESH_COOLDOWN_MS) {
2304
+ return false;
2305
+ }
2306
+ if (!this.menuScheduleRefreshInFlight) {
2307
+ this.lastMenuScheduleRefreshAt = now;
2308
+ this.menuScheduleRefreshInFlight = Promise.all([
2309
+ this.menu.loadMenuList(),
2310
+ this.schedule.loadAllSchedule()
2311
+ ]).then(() => void 0).catch((error) => {
2312
+ this.logWarning("刷新菜单/日程缓存失败,继续使用现有缓存", {
2313
+ error: error instanceof Error ? error.message : String(error)
2314
+ });
2315
+ }).finally(() => {
2316
+ this.menuScheduleRefreshInFlight = null;
2317
+ });
2318
+ }
2319
+ await this.menuScheduleRefreshInFlight;
2320
+ return true;
2321
+ }
2280
2322
  /**
2281
2323
  * 执行 sales 搜索并登记可见订单号。
2282
2324
  * 搜索参数完全透传后端,OS 不做过滤、筛选、排序。
@@ -3779,10 +3821,22 @@ var Server = class {
3779
3821
  data: (normalized == null ? void 0 : normalized.data) ?? null
3780
3822
  };
3781
3823
  }
3782
- return this.withSyncedOrderIdInCheckoutResponse(
3824
+ const response = this.withSyncedOrderIdInCheckoutResponse(
3783
3825
  syncResult.normalizedResponse,
3784
3826
  syncResult.syncedOrder
3785
3827
  );
3828
+ const syncedOrder = syncResult.syncedOrder;
3829
+ if (syncedOrder && this.shouldBuildSmallTicketData(syncResult.checkoutData) && this.isSalesOrderFullyPaid(syncedOrder)) {
3830
+ await this.dispatchLocalReceiptPrint({
3831
+ checkoutData: syncResult.checkoutData,
3832
+ order: syncedOrder,
3833
+ response: syncResult.normalizedResponse,
3834
+ requireFullyPaid: true,
3835
+ // print_all 的 type=0 是收据打印;不要沿用同步成功后的券/手环打印 type=99。
3836
+ isManualPrint: true
3837
+ });
3838
+ }
3839
+ return response;
3786
3840
  } catch (error) {
3787
3841
  const backendError = this.extractBackendErrorResponse(error);
3788
3842
  if (backendError) {
@@ -5072,13 +5126,16 @@ var Server = class {
5072
5126
  let activeMenuList = [];
5073
5127
  if (menu_list_ids && Array.isArray(menu_list_ids) && menu_list_ids.length > 0) {
5074
5128
  const tMenu = performance.now();
5075
- const menuList = this.menu.getMenuByIds(menu_list_ids);
5076
- activeMenuList = menuList.filter((menu) => {
5129
+ const getActiveMenus = () => this.menu.getMenuByIds(menu_list_ids).filter((menu) => {
5077
5130
  var _a;
5078
5131
  return ((_a = this.schedule) == null ? void 0 : _a.getDateIsInSchedule(schedule_datetime, menu.schedule)) || false;
5079
5132
  });
5133
+ activeMenuList = getActiveMenus();
5134
+ if (!activeMenuList.length && await this.refreshMenuScheduleCacheAfterEmptyResult()) {
5135
+ activeMenuList = getActiveMenus();
5136
+ }
5080
5137
  (0, import_product.perfMark)("computeQuery.filterActiveMenu", performance.now() - tMenu, {
5081
- totalMenu: menuList.length,
5138
+ totalMenu: menu_list_ids.length,
5082
5139
  activeMenu: activeMenuList.length
5083
5140
  });
5084
5141
  }
@@ -280,6 +280,13 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
280
280
  confirmPendingVoucherPayments?: boolean;
281
281
  enhancePayload?: SubmitPayloadEnhancer;
282
282
  }): Promise<T>;
283
+ /**
284
+ * 默认保持 WebPOS 的本地待同步订单模式;需要云端确认后才算成功的渠道可覆盖此策略。
285
+ * otherParams.checkoutSyncTaskEnabled 优先,便于同一 solution 按入口恢复旧行为。
286
+ */
287
+ protected shouldUseCheckoutSyncTask(): boolean;
288
+ /** 可由特定 solution 为真实 checkout 补充默认收据数据请求。 */
289
+ protected getDefaultCheckoutSmallTicketDataFlag(): number | undefined;
283
290
  printLocalOrderReceipt<T = any>(lookup?: BaseSalesPrintLocalOrderReceiptParams): Promise<T>;
284
291
  private getSubmitPaymentStatus;
285
292
  syncPaymentsToOrder<T = any>(params: SyncPaymentsToOrderParams): Promise<SyncPaymentsToOrderResult<T>>;
@@ -1008,7 +1008,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1008
1008
  return isChanged;
1009
1009
  }
1010
1010
  async initialize(core, options = {}) {
1011
- var _a, _b;
1011
+ var _a, _b, _c, _d;
1012
1012
  this.core = core;
1013
1013
  this.initializeOptions = options || {};
1014
1014
  this.paymentNumberDevicePrefix = null;
@@ -1019,10 +1019,9 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1019
1019
  this.request = core.getPlugin("request");
1020
1020
  this.appPlugin = core.getPlugin("app");
1021
1021
  if (!this.appPlugin) {
1022
- throw new Error("Checkout 解决方案需要 app 插件支持");
1023
1022
  }
1024
- const app = this.appPlugin.getApp();
1025
- this.logger = app.logger;
1023
+ const app = (_c = (_b = this.appPlugin) == null ? void 0 : _b.getApp) == null ? void 0 : _c.call(_b);
1024
+ this.logger = app == null ? void 0 : app.logger;
1026
1025
  const targetCacheData = this.readSessionCacheData();
1027
1026
  const moduleNames = this.getRegisteredModuleNames();
1028
1027
  moduleNames.forEach((step) => {
@@ -1047,7 +1046,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1047
1046
  if (this.store.schedule && !this.isScheduleListLoaded(this.store.schedule)) {
1048
1047
  await this.store.schedule.loadAllSchedule();
1049
1048
  }
1050
- if (this.store.order && typeof ((_b = this.otherParams) == null ? void 0 : _b.enableTempOrderPersist) === "boolean") {
1049
+ if (this.store.order && typeof ((_d = this.otherParams) == null ? void 0 : _d.enableTempOrderPersist) === "boolean") {
1051
1050
  this.store.order.setEnableTempOrderPersist(
1052
1051
  this.otherParams.enableTempOrderPersist
1053
1052
  );
@@ -1901,6 +1900,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1901
1900
  throw new Error("BaseSales 解决方案需要 order 模块支持");
1902
1901
  }
1903
1902
  const inferredPaymentStatus = this.getSubmitPaymentStatus(params == null ? void 0 : params.paymentStatus);
1903
+ const smallTicketDataFlag = (params == null ? void 0 : params.smallTicketDataFlag) ?? this.getDefaultCheckoutSmallTicketDataFlag();
1904
1904
  const submitParams = {
1905
1905
  cacheId: this.cacheId,
1906
1906
  platform: (_a = this.otherParams) == null ? void 0 : _a.platform,
@@ -1910,11 +1910,11 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1910
1910
  request_unique_idempotency_token: this.store.order.generateIdempotencyToken(),
1911
1911
  ...(params == null ? void 0 : params.payments) !== void 0 ? { payments: params.payments } : {},
1912
1912
  ...inferredPaymentStatus !== void 0 ? { paymentStatus: inferredPaymentStatus } : {},
1913
- ...(params == null ? void 0 : params.smallTicketDataFlag) !== void 0 ? { smallTicketDataFlag: params.smallTicketDataFlag } : {},
1913
+ ...smallTicketDataFlag !== void 0 ? { smallTicketDataFlag } : {},
1914
1914
  ...(params == null ? void 0 : params.confirmPendingVoucherPayments) !== void 0 ? { confirmPendingVoucherPayments: params.confirmPendingVoucherPayments } : {},
1915
1915
  ...(params == null ? void 0 : params.enhancePayload) !== void 0 ? { enhancePayload: params.enhancePayload } : {}
1916
1916
  };
1917
- return this.store.order.submitTempOrder(submitParams);
1917
+ return this.shouldUseCheckoutSyncTask() ? this.store.order.submitTempOrder(submitParams) : this.store.order.submitTempOrderAsync(submitParams);
1918
1918
  }
1919
1919
  async saveSalesOrderDraft(params) {
1920
1920
  var _a, _b, _c, _d;
@@ -1936,20 +1936,35 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1936
1936
  throw new Error("BaseSales 解决方案需要 order 模块支持");
1937
1937
  }
1938
1938
  const inferredPaymentStatus = this.getSubmitPaymentStatus(params == null ? void 0 : params.paymentStatus);
1939
+ const smallTicketDataFlag = (params == null ? void 0 : params.smallTicketDataFlag) ?? this.getDefaultCheckoutSmallTicketDataFlag();
1939
1940
  const submitParams = {
1940
1941
  cacheId: this.cacheId,
1941
1942
  platform: (_a = this.otherParams) == null ? void 0 : _a.platform,
1942
1943
  businessCode: ((_b = this.otherParams) == null ? void 0 : _b.businessCode) || ((_c = this.otherParams) == null ? void 0 : _c.business_code),
1943
1944
  channel: this.getSubmitOrderSalesChannel(),
1944
1945
  type: (_d = this.otherParams) == null ? void 0 : _d.type,
1946
+ request_unique_idempotency_token: this.store.order.generateIdempotencyToken(),
1945
1947
  ...(params == null ? void 0 : params.payments) !== void 0 ? { payments: params.payments } : {},
1946
1948
  ...inferredPaymentStatus !== void 0 ? { paymentStatus: inferredPaymentStatus } : {},
1947
- ...(params == null ? void 0 : params.smallTicketDataFlag) !== void 0 ? { smallTicketDataFlag: params.smallTicketDataFlag } : {},
1949
+ ...smallTicketDataFlag !== void 0 ? { smallTicketDataFlag } : {},
1948
1950
  ...(params == null ? void 0 : params.confirmPendingVoucherPayments) !== void 0 ? { confirmPendingVoucherPayments: params.confirmPendingVoucherPayments } : {},
1949
1951
  ...(params == null ? void 0 : params.enhancePayload) !== void 0 ? { enhancePayload: params.enhancePayload } : {}
1950
1952
  };
1951
1953
  return this.store.order.submitTempOrderAsync(submitParams);
1952
1954
  }
1955
+ /**
1956
+ * 默认保持 WebPOS 的本地待同步订单模式;需要云端确认后才算成功的渠道可覆盖此策略。
1957
+ * otherParams.checkoutSyncTaskEnabled 优先,便于同一 solution 按入口恢复旧行为。
1958
+ */
1959
+ shouldUseCheckoutSyncTask() {
1960
+ var _a;
1961
+ const configured = (_a = this.otherParams) == null ? void 0 : _a.checkoutSyncTaskEnabled;
1962
+ return typeof configured === "boolean" ? configured : true;
1963
+ }
1964
+ /** 可由特定 solution 为真实 checkout 补充默认收据数据请求。 */
1965
+ getDefaultCheckoutSmallTicketDataFlag() {
1966
+ return void 0;
1967
+ }
1953
1968
  async printLocalOrderReceipt(lookup) {
1954
1969
  var _a, _b, _c, _d, _e, _f, _g;
1955
1970
  if (!this.store.order) {
@@ -2009,6 +2024,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
2009
2024
  const channel = params.channel ?? this.getSubmitOrderSalesChannel();
2010
2025
  const syncParams = {
2011
2026
  ...params,
2027
+ checkoutSyncTaskEnabled: this.shouldUseCheckoutSyncTask(),
2012
2028
  ...businessCode !== void 0 ? { businessCode } : {},
2013
2029
  ...channel !== void 0 ? { channel } : {}
2014
2030
  };
@@ -10,6 +10,7 @@ import { ITime } from '../../modules/Date/types';
10
10
  import dayjs from 'dayjs';
11
11
  import { LoadScheduleAvailableDateParams } from '../../modules/Schedule/types';
12
12
  import { IHolder, IFetchHolderAccountsParams } from '../../modules/AccountList/types';
13
+ import { IAppendFormRecordParams } from '../../modules/Holder/types';
13
14
  export declare class BookingByStepImpl extends BaseModule implements Module {
14
15
  protected defaultName: string;
15
16
  protected defaultVersion: string;
@@ -126,6 +127,20 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
126
127
  * @param params
127
128
  */
128
129
  fetchHolderAccountsAsync(params: IFetchHolderAccountsParams): Promise<void>;
130
+ /**
131
+ * 获取 holder 表单 map
132
+ */
133
+ getHolderFormMap(): import("../../modules").HolderFormMap;
134
+ /**
135
+ * 登录后或外部触发时,按当前 holderMap 批量刷新所有表单的 records
136
+ */
137
+ refreshAllHolderFormRecords(params?: {
138
+ customer_id?: number;
139
+ }): Promise<import("../../modules").HolderFormMap>;
140
+ /**
141
+ * 添加表单记录
142
+ */
143
+ appendFormRecord(params: IAppendFormRecordParams): import("../../modules").IFormRecord;
129
144
  setDateRange(dateRange: ITime[]): Promise<void>;
130
145
  clearDateRange(): void;
131
146
  getDateRange(): Promise<ITime[]>;
@@ -302,7 +317,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
302
317
  autoSelectAllProductResources(resources_code: string, timeSlots?: TimeSliceItem): {
303
318
  errorList: any[];
304
319
  };
305
- getTimeSlotByAllResources(resources_code: string): any[];
320
+ getTimeSlotByAllResources(resources_code: string, split?: number): any[];
306
321
  getTimeSlotByAllResourcesForDate({ resources_code, startDate, endDate }: {
307
322
  resources_code: string;
308
323
  startDate: string;
@@ -311,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
311
326
  date: string;
312
327
  status: string;
313
328
  week: string;
314
- weekNum: 0 | 2 | 1 | 3 | 4 | 5 | 6;
329
+ weekNum: 0 | 1 | 2 | 3 | 4 | 5 | 6;
315
330
  }[]>;
316
331
  submitTimeSlot(timeSlots: TimeSliceItem): void;
317
332
  private getScheduleDataByIds;
@@ -89,6 +89,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
89
89
  }
90
90
  const moduleArr = [
91
91
  "accountList",
92
+ "holder",
92
93
  "cart",
93
94
  "schedule",
94
95
  "summary",
@@ -379,6 +380,27 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
379
380
  }
380
381
  return this.store.accountList.fetchHolderAccounts(params);
381
382
  }
383
+ /**
384
+ * 获取 holder 表单 map
385
+ */
386
+ getHolderFormMap() {
387
+ return this.store.holder.getHolderFormMap();
388
+ }
389
+ /**
390
+ * 登录后或外部触发时,按当前 holderMap 批量刷新所有表单的 records
391
+ */
392
+ async refreshAllHolderFormRecords(params) {
393
+ return this.store.holder.refreshAllFormRecords({
394
+ customer_id: params == null ? void 0 : params.customer_id,
395
+ useCache: false
396
+ });
397
+ }
398
+ /**
399
+ * 添加表单记录
400
+ */
401
+ appendFormRecord(params) {
402
+ return this.store.holder.appendFormRecord(params);
403
+ }
382
404
  // 设置日期范围,注入到日期模块中
383
405
  async setDateRange(dateRange) {
384
406
  this.store.date.setDateRange(dateRange);
@@ -486,6 +508,14 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
486
508
  date = (normalProductCartItem == null ? void 0 : normalProductCartItem.start_date) || "";
487
509
  }
488
510
  this.updateQuotationPriceAndCart(date);
511
+ try {
512
+ const customerId = Number(accountInfo.id);
513
+ await this.refreshAllHolderFormRecords({
514
+ customer_id: customerId
515
+ });
516
+ } catch (error) {
517
+ console.error("[BookingByStep] 登录后刷新 holder 表单失败", error);
518
+ }
489
519
  }
490
520
  } else {
491
521
  throw new Error(`没有找到${accountId}账户`);
@@ -512,10 +542,11 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
512
542
  }
513
543
  // 购物车提交订单
514
544
  async submitOrder(extraData) {
545
+ var _a;
515
546
  const cartItems = this.store.cart.getItems();
516
547
  const newCartItems = (0, import_lodash_es.cloneDeep)(cartItems);
517
548
  newCartItems.forEach((item) => {
518
- var _a;
549
+ var _a2;
519
550
  if (item._origin.resources && item._origin.resources.length) {
520
551
  item._origin.resources = item._origin.resources.map((n) => {
521
552
  const newResourcesItem = (0, import_lodash_es.cloneDeep)(n);
@@ -525,7 +556,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
525
556
  return { ...newResourcesItem };
526
557
  });
527
558
  const { currentCapacity, formatCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(item);
528
- if (!((_a = item._origin) == null ? void 0 : _a.metadata)) {
559
+ if (!((_a2 = item._origin) == null ? void 0 : _a2.metadata)) {
529
560
  item._origin.metadata = {};
530
561
  }
531
562
  item._origin.metadata.capacity = formatCapacity;
@@ -543,6 +574,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
543
574
  cartItems: newCartItems,
544
575
  type,
545
576
  platform: this.platform,
577
+ business_code: (_a = this.otherParams) == null ? void 0 : _a.business_code,
546
578
  extraData
547
579
  }
548
580
  });
@@ -628,6 +660,15 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
628
660
  account = activeAccount;
629
661
  }
630
662
  }
663
+ try {
664
+ this.store.holder.ensureFormByProduct({
665
+ product: productData,
666
+ shop_id: (productData == null ? void 0 : productData.shop_id) || "",
667
+ useCache: true
668
+ });
669
+ } catch (error) {
670
+ console.error("[BookingByStep] 加载 holder 表单失败", error);
671
+ }
631
672
  const flag = this.store.cart.mergeCartItemByRowKey({
632
673
  rowKey,
633
674
  quantity,
@@ -1150,7 +1191,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1150
1191
  }
1151
1192
  const totalCapacity = (countMap[n.id] || []).reduce(
1152
1193
  (sum, item) => {
1153
- const hasOverlap = !(0, import_dayjs.default)(item.time.start_at).isAfter((0, import_dayjs.default)(timeSlots.start_at)) && !(0, import_dayjs.default)(item.time.end_at).isBefore((0, import_dayjs.default)(timeSlots.end_at));
1194
+ const hasOverlap = (0, import_dayjs.default)(item.time.start_at).isBefore((0, import_dayjs.default)(timeSlots.end_at)) && (0, import_dayjs.default)(item.time.end_at).isAfter((0, import_dayjs.default)(timeSlots.start_at));
1154
1195
  return hasOverlap ? sum + item.pax : sum;
1155
1196
  },
1156
1197
  0
@@ -1232,9 +1273,10 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1232
1273
  }
1233
1274
  );
1234
1275
  cartItems2.forEach((item, index) => {
1235
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
1276
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
1236
1277
  const { currentCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(item);
1237
- if (item._origin.start_time && !(timeSlots == null ? void 0 : timeSlots.start_time)) {
1278
+ const hasOriginTimeSlot = Boolean(item._origin.start_time) && Boolean(item._origin.end_time) && !(timeSlots == null ? void 0 : timeSlots.start_time);
1279
+ if (hasOriginTimeSlot) {
1238
1280
  recordTimeSlots = {
1239
1281
  start_time: item._origin.start_time,
1240
1282
  end_time: item._origin.end_time,
@@ -1246,13 +1288,11 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1246
1288
  const currentResourceConfig = (_c = (_b = (_a2 = item._productOrigin) == null ? void 0 : _a2.product_resource) == null ? void 0 : _b.resources) == null ? void 0 : _c.find(
1247
1289
  (n) => n.code === resources_code
1248
1290
  );
1249
- if (index !== 0 && recordTimeSlots && (currentResourceConfig == null ? void 0 : currentResourceConfig.type) === "single" && ((_d = item._productOrigin) == null ? void 0 : _d.duration) && !hasFlexibleProduct) {
1250
- let start_at = (0, import_dayjs.default)(recordTimeSlots.end_time).add(
1251
- ((_f = (_e = item._productOrigin) == null ? void 0 : _e.duration) == null ? void 0 : _f.value) || 10,
1252
- "minutes"
1253
- );
1291
+ if (index !== 0 && recordTimeSlots && (currentResourceConfig == null ? void 0 : currentResourceConfig.type) === "single" && ((_d = item._productOrigin) == null ? void 0 : _d.duration) && !hasFlexibleProduct && !hasOriginTimeSlot) {
1292
+ const recordEndAt = recordTimeSlots.end_at ? (0, import_dayjs.default)(recordTimeSlots.end_at) : (0, import_dayjs.default)(`${item.start_date} ${recordTimeSlots.end_time}`);
1293
+ let start_at = recordEndAt;
1254
1294
  let end_at = start_at.add(
1255
- ((_h = (_g = item._productOrigin) == null ? void 0 : _g.duration) == null ? void 0 : _h.value) || 10,
1295
+ ((_f = (_e = item._productOrigin) == null ? void 0 : _e.duration) == null ? void 0 : _f.value) || 10,
1256
1296
  "minutes"
1257
1297
  );
1258
1298
  recordTimeSlots = {
@@ -1306,7 +1346,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1306
1346
  const allCartItems = (0, import_lodash_es.cloneDeep)(this.store.cart.getItems());
1307
1347
  let selectedResources = [];
1308
1348
  const resources2 = (0, import_lodash_es.cloneDeep)(
1309
- ((_j = (_i = item._productOrigin) == null ? void 0 : _i.product_resource) == null ? void 0 : _j.resources) || []
1349
+ ((_h = (_g = item._productOrigin) == null ? void 0 : _g.product_resource) == null ? void 0 : _h.resources) || []
1310
1350
  );
1311
1351
  const currentResourcesRenderList = [];
1312
1352
  resources2.forEach((n) => {
@@ -1354,11 +1394,11 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1354
1394
  return recordCount >= currentCapacity;
1355
1395
  });
1356
1396
  });
1357
- const targetRenderList = (_k = productResources.find(
1397
+ const targetRenderList = (_i = productResources.find(
1358
1398
  (n) => n.code === resources_code
1359
- )) == null ? void 0 : _k.renderList;
1399
+ )) == null ? void 0 : _i.renderList;
1360
1400
  if (targetRenderList && targetRenderList.length > 0) {
1361
- if ((_l = item._origin.resources) == null ? void 0 : _l.some(
1401
+ if ((_j = item._origin.resources) == null ? void 0 : _j.some(
1362
1402
  (n) => n.form_id === targetRenderList[0].form_id
1363
1403
  )) {
1364
1404
  return;
@@ -1366,7 +1406,9 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1366
1406
  const fastestResource = (0, import_timeslots.findFastestAvailableResource)({
1367
1407
  resources: targetRenderList,
1368
1408
  currentCapacity,
1369
- countMap: selectResourcesMap
1409
+ countMap: selectResourcesMap,
1410
+ targetDate: (_k = dateRange == null ? void 0 : dateRange[0]) == null ? void 0 : _k.date,
1411
+ durationMinutes: ((_l = item == null ? void 0 : item.duration) == null ? void 0 : _l.value) || ((_n = (_m = item == null ? void 0 : item._productOrigin) == null ? void 0 : _m.duration) == null ? void 0 : _n.value) || 10
1370
1412
  });
1371
1413
  const targetResource = fastestResource || targetRenderList[0];
1372
1414
  targetResource.capacity = currentCapacity;
@@ -1403,7 +1445,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1403
1445
  return { errorList };
1404
1446
  }
1405
1447
  // 从购物车中获取已经分配好第一步资源的所有时间片
1406
- getTimeSlotByAllResources(resources_code) {
1448
+ getTimeSlotByAllResources(resources_code, split = 10) {
1407
1449
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1408
1450
  let dateRange = this.store.date.getDateRange();
1409
1451
  const resources = [];
@@ -1561,7 +1603,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1561
1603
  resourcesMap,
1562
1604
  duration,
1563
1605
  currentDate: dateRange[0].date,
1564
- split: 10,
1606
+ split,
1565
1607
  resourcesUseableMap,
1566
1608
  capacity: maxCapacity,
1567
1609
  cut_off_time: maxCutOffTime,
@@ -1,4 +1,4 @@
1
- import { ProductList, CartModule, ProductData, AccountModule, AccountListModule, DateModule, GuestListModule, OrderModule, PaymentModule, ResourceListModule, StepModule, SummaryModule, SalesSummaryModule, ScheduleModule, ScanOrderLoggerModule } from '../../modules';
1
+ import { ProductList, CartModule, ProductData, AccountModule, AccountListModule, DateModule, GuestListModule, OrderModule, PaymentModule, ResourceListModule, StepModule, SummaryModule, SalesSummaryModule, ScheduleModule, ScanOrderLoggerModule, HolderModule } from '../../modules';
2
2
  export interface BookingByStepState {
3
3
  cart: CartModule;
4
4
  summary: SummaryModule;
@@ -16,6 +16,7 @@ export interface BookingByStepState {
16
16
  schedule: ScheduleModule;
17
17
  salesSummary?: SalesSummaryModule;
18
18
  scanOrderLogger?: ScanOrderLoggerModule;
19
+ holder: HolderModule;
19
20
  }
20
21
  export declare function createModule<T extends keyof BookingByStepState>(moduleName: T, solutionName: string, name?: string, version?: string): BookingByStepState[T];
21
22
  export declare enum BookingByStepHooks {
@@ -81,6 +81,11 @@ function createModule(moduleName, solutionName, name, version) {
81
81
  `${solutionName}_${name || moduleName}`,
82
82
  version
83
83
  );
84
+ case "holder":
85
+ return new import_modules.HolderModule(
86
+ `${solutionName}_${name || moduleName}`,
87
+ version
88
+ );
84
89
  default:
85
90
  throw new Error(`Unknown module type: ${moduleName}`);
86
91
  }
@@ -49,8 +49,27 @@ var formatDefaultCapacitys = ({
49
49
  const id = d.bundle_product_id;
50
50
  const variantId = d.bundle_variant_id;
51
51
  const item = ((capacity == null ? void 0 : capacity.package) || []).find(
52
- (item2) => item2.product_id === id || item2.product_id === variantId
52
+ (item2) => item2.product_id == id || item2.product_id == variantId
53
53
  );
54
+ if (!item && (window == null ? void 0 : window.sendWarningLog)) {
55
+ window.sendWarningLog({
56
+ title: "未找到套餐 capacity 配置",
57
+ content: [
58
+ {
59
+ key: "product_id",
60
+ value: id
61
+ },
62
+ {
63
+ key: "variant_id",
64
+ value: variantId
65
+ },
66
+ {
67
+ key: "package",
68
+ value: JSON.stringify((capacity == null ? void 0 : capacity.package) || [])
69
+ }
70
+ ]
71
+ });
72
+ }
54
73
  return {
55
74
  id,
56
75
  value: item ? d.num || 0 : 0,
@@ -19,10 +19,12 @@ export declare function calculateResourceAvailableTime({ resource, timeSlots, cu
19
19
  * @param countMap 已预约数量映射
20
20
  * @returns 最快可用的资源
21
21
  */
22
- export declare function findFastestAvailableResource({ resources, currentCapacity, countMap, }: {
22
+ export declare function findFastestAvailableResource({ resources, currentCapacity, countMap, targetDate, durationMinutes, }: {
23
23
  resources: ResourceItem[];
24
24
  currentCapacity?: number;
25
25
  countMap?: Record<number, number>;
26
+ targetDate?: string | Dayjs;
27
+ durationMinutes?: number;
26
28
  }): ResourceItem | null;
27
29
  /**
28
30
  * 给定一个时间列表,通过开始和结束时间过滤出符合条件的时间段