@pisell/pisellos 0.0.499 → 0.0.501

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 (58) hide show
  1. package/dist/model/strategy/adapter/itemRule/adapter.d.ts +8 -0
  2. package/dist/model/strategy/adapter/itemRule/adapter.js +52 -8
  3. package/dist/model/strategy/adapter/itemRule/examples.d.ts +15 -0
  4. package/dist/model/strategy/adapter/itemRule/examples.js +68 -1
  5. package/dist/model/strategy/adapter/itemRule/index.d.ts +1 -1
  6. package/dist/model/strategy/adapter/itemRule/index.js +1 -1
  7. package/dist/model/strategy/adapter/itemRule/type.d.ts +20 -1
  8. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  9. package/dist/modules/Order/index.d.ts +6 -0
  10. package/dist/modules/Order/index.js +60 -40
  11. package/dist/modules/Order/types.d.ts +4 -0
  12. package/dist/modules/Order/utils.d.ts +31 -0
  13. package/dist/modules/Order/utils.js +118 -13
  14. package/dist/modules/ProductList/index.js +2 -2
  15. package/dist/modules/Quotation/index.js +6 -3
  16. package/dist/modules/SalesSummary/types.d.ts +2 -1
  17. package/dist/modules/SalesSummary/utils.js +10 -10
  18. package/dist/modules/Schedule/utils.d.ts +1 -1
  19. package/dist/solution/BookingByStep/index.d.ts +2 -2
  20. package/dist/solution/ScanOrder/index.d.ts +7 -0
  21. package/dist/solution/ScanOrder/index.js +284 -67
  22. package/dist/solution/ScanOrder/types.d.ts +22 -5
  23. package/dist/solution/ScanOrder/utils.d.ts +26 -0
  24. package/dist/solution/ScanOrder/utils.js +191 -44
  25. package/dist/solution/VenueBooking/index.d.ts +14 -0
  26. package/dist/solution/VenueBooking/index.js +318 -144
  27. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  28. package/dist/solution/VenueBooking/utils/dateSummary.js +6 -4
  29. package/dist/solution/VenueBooking/utils/slotMerge.js +1 -2
  30. package/lib/model/strategy/adapter/itemRule/adapter.d.ts +8 -0
  31. package/lib/model/strategy/adapter/itemRule/adapter.js +41 -2
  32. package/lib/model/strategy/adapter/itemRule/examples.d.ts +15 -0
  33. package/lib/model/strategy/adapter/itemRule/examples.js +47 -0
  34. package/lib/model/strategy/adapter/itemRule/index.d.ts +1 -1
  35. package/lib/model/strategy/adapter/itemRule/index.js +2 -0
  36. package/lib/model/strategy/adapter/itemRule/type.d.ts +20 -1
  37. package/lib/modules/Order/index.d.ts +6 -0
  38. package/lib/modules/Order/index.js +35 -37
  39. package/lib/modules/Order/types.d.ts +4 -0
  40. package/lib/modules/Order/utils.d.ts +31 -0
  41. package/lib/modules/Order/utils.js +97 -9
  42. package/lib/modules/ProductList/index.js +3 -2
  43. package/lib/modules/Quotation/index.js +3 -0
  44. package/lib/modules/SalesSummary/types.d.ts +2 -1
  45. package/lib/modules/SalesSummary/utils.js +2 -2
  46. package/lib/modules/Schedule/utils.d.ts +1 -1
  47. package/lib/solution/BookingByStep/index.d.ts +2 -2
  48. package/lib/solution/ScanOrder/index.d.ts +7 -0
  49. package/lib/solution/ScanOrder/index.js +162 -18
  50. package/lib/solution/ScanOrder/types.d.ts +22 -5
  51. package/lib/solution/ScanOrder/utils.d.ts +26 -0
  52. package/lib/solution/ScanOrder/utils.js +128 -19
  53. package/lib/solution/VenueBooking/index.d.ts +14 -0
  54. package/lib/solution/VenueBooking/index.js +156 -30
  55. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  56. package/lib/solution/VenueBooking/utils/dateSummary.js +13 -4
  57. package/lib/solution/VenueBooking/utils/slotMerge.js +1 -2
  58. package/package.json +1 -1
@@ -24,16 +24,20 @@ __export(utils_exports, {
24
24
  buildItemRuleBusinessData: () => buildItemRuleBusinessData,
25
25
  buildProductKey: () => buildProductKey,
26
26
  buildQuantityLimitIndex: () => buildQuantityLimitIndex,
27
+ collectLinkProductIdsFromReservationRules: () => collectLinkProductIdsFromReservationRules,
27
28
  createEmptySummary: () => createEmptySummary,
28
29
  extractStrategyModelIdsFromTableConfig: () => extractStrategyModelIdsFromTableConfig,
29
30
  getProductIdentityIndex: () => getProductIdentityIndex,
30
31
  getSafeProductNum: () => getSafeProductNum,
31
32
  getTopLevelProductId: () => getTopLevelProductId,
32
33
  getTopLevelVariantId: () => getTopLevelVariantId,
34
+ hasCustomCapacityProduct: () => hasCustomCapacityProduct,
33
35
  isIdentityMatch: () => isIdentityMatch,
34
36
  normalizeEnabledItemRuleIds: () => normalizeEnabledItemRuleIds,
35
37
  normalizeItemRuleStrategies: () => normalizeItemRuleStrategies,
36
38
  normalizeOrderProduct: () => normalizeOrderProduct,
39
+ pickFirstCustomCapacityPaxBounds: () => pickFirstCustomCapacityPaxBounds,
40
+ pickFirstDurationMinutesFromProducts: () => pickFirstDurationMinutesFromProducts,
37
41
  resolveSkuMatchedQuantityLimits: () => resolveSkuMatchedQuantityLimits,
38
42
  toBoolean: () => toBoolean,
39
43
  toNonNegativeInt: () => toNonNegativeInt,
@@ -160,18 +164,20 @@ function buildQuantityLimitIndex(limits) {
160
164
  const exactLimitMap = /* @__PURE__ */ new Map();
161
165
  const productLimitMap = /* @__PURE__ */ new Map();
162
166
  for (const limit of limits) {
163
- for (const target of limit.targets || []) {
164
- const productId = Number(target.product_id);
165
- if (!Number.isFinite(productId) || productId <= 0)
166
- continue;
167
- const variantId = Number(target.product_variant_id);
168
- const hasVariant = Number.isFinite(variantId) && variantId > 0;
169
- if (hasVariant) {
170
- const exactKey = buildProductKey(productId, variantId);
171
- const existed2 = exactLimitMap.get(exactKey) || [];
172
- exactLimitMap.set(exactKey, [...existed2, limit]);
173
- continue;
174
- }
167
+ const targets = limit.targets || [];
168
+ if (targets.length !== 1)
169
+ continue;
170
+ const target = targets[0];
171
+ const productId = Number(target.product_id);
172
+ if (!Number.isFinite(productId) || productId <= 0)
173
+ continue;
174
+ const variantId = Number(target.product_variant_id);
175
+ const hasVariant = Number.isFinite(variantId) && variantId > 0;
176
+ if (hasVariant) {
177
+ const exactKey = buildProductKey(productId, variantId);
178
+ const existed = exactLimitMap.get(exactKey) || [];
179
+ exactLimitMap.set(exactKey, [...existed, limit]);
180
+ } else {
175
181
  const existed = productLimitMap.get(productId) || [];
176
182
  productLimitMap.set(productId, [...existed, limit]);
177
183
  }
@@ -192,29 +198,66 @@ function aggregateItemRuleLimit(matchedLimits) {
192
198
  return null;
193
199
  let min;
194
200
  let max;
201
+ let remainingMax;
195
202
  let exact;
196
203
  let mustInclude = false;
204
+ let maxSourceLimit;
205
+ let remainingMaxSourceLimit;
206
+ let exactSourceLimit;
207
+ let minSourceLimit;
208
+ let firstMessagedLimit;
197
209
  for (const limit of matchedLimits) {
198
210
  if (typeof limit.requiredMin === "number" && Number.isFinite(limit.requiredMin)) {
199
- min = min === void 0 ? limit.requiredMin : Math.max(min, limit.requiredMin);
211
+ if (min === void 0 || limit.requiredMin > min) {
212
+ min = limit.requiredMin;
213
+ minSourceLimit = limit;
214
+ }
200
215
  }
201
216
  if (typeof limit.requiredMax === "number" && Number.isFinite(limit.requiredMax)) {
202
- max = max === void 0 ? limit.requiredMax : Math.min(max, limit.requiredMax);
217
+ if (max === void 0 || limit.requiredMax < max) {
218
+ max = limit.requiredMax;
219
+ maxSourceLimit = limit;
220
+ }
221
+ }
222
+ if (typeof limit.remainingMax === "number" && Number.isFinite(limit.remainingMax)) {
223
+ if (remainingMax === void 0 || limit.remainingMax < remainingMax) {
224
+ remainingMax = limit.remainingMax;
225
+ remainingMaxSourceLimit = limit;
226
+ }
203
227
  }
204
228
  if (typeof limit.requiredExact === "number" && Number.isFinite(limit.requiredExact)) {
205
229
  exact = limit.requiredExact;
230
+ exactSourceLimit = limit;
206
231
  }
207
232
  mustInclude = mustInclude || Boolean(limit.mustInclude);
233
+ if (!firstMessagedLimit && limit.validationMessage) {
234
+ firstMessagedLimit = limit;
235
+ }
208
236
  }
209
237
  if (typeof exact === "number" && Number.isFinite(exact)) {
210
238
  min = exact;
211
239
  max = exact;
212
240
  }
241
+ const maxMessageSource = maxSourceLimit || remainingMaxSourceLimit || exactSourceLimit || firstMessagedLimit;
242
+ const minMessageSource = minSourceLimit || exactSourceLimit || firstMessagedLimit;
243
+ const maxValidationMessage = maxMessageSource == null ? void 0 : maxMessageSource.validationMessage;
244
+ const rawMaxValidationMessage = maxMessageSource == null ? void 0 : maxMessageSource.rawValidationMessage;
245
+ const minValidationMessage = minMessageSource == null ? void 0 : minMessageSource.validationMessage;
246
+ const rawMinValidationMessage = minMessageSource == null ? void 0 : minMessageSource.rawValidationMessage;
247
+ const validationMessage = maxValidationMessage ?? minValidationMessage;
248
+ const rawValidationMessage = rawMaxValidationMessage ?? rawMinValidationMessage;
213
249
  return {
214
250
  min,
215
251
  max,
252
+ remainingMax,
216
253
  exact,
217
- mustInclude
254
+ mustInclude,
255
+ validationMessage,
256
+ rawValidationMessage,
257
+ maxValidationMessage,
258
+ rawMaxValidationMessage,
259
+ minValidationMessage,
260
+ rawMinValidationMessage
218
261
  };
219
262
  }
220
263
  function buildItemRuleBusinessData(params) {
@@ -294,13 +337,13 @@ function getProductIdentityIndex(products, identity) {
294
337
  return products.findIndex((item) => isIdentityMatch(item, identity));
295
338
  }
296
339
  function normalizeOrderProduct(product) {
297
- var _a;
340
+ var _a, _b;
298
341
  const metadata = { ...product.metadata || {} };
299
342
  if (product.identity_key && !metadata.unique_identification_number) {
300
343
  metadata.unique_identification_number = product.identity_key;
301
344
  }
302
- const resolvedOriginalPrice = product.original_price || "0.00";
303
345
  const resolvedSellingPrice = product.selling_price || "0.00";
346
+ const resolvedOriginalPrice = product.original_price || resolvedSellingPrice;
304
347
  if (metadata.main_product_original_price === void 0) {
305
348
  metadata.main_product_original_price = resolvedOriginalPrice;
306
349
  }
@@ -308,7 +351,7 @@ function normalizeOrderProduct(product) {
308
351
  metadata.main_product_selling_price = resolvedSellingPrice;
309
352
  }
310
353
  if (metadata.source_product_price === void 0) {
311
- metadata.source_product_price = ((_a = product._origin) == null ? void 0 : _a.original_price) ?? resolvedOriginalPrice;
354
+ metadata.source_product_price = ((_a = product._origin) == null ? void 0 : _a.price) ?? ((_b = product._origin) == null ? void 0 : _b.base_price) ?? resolvedSellingPrice;
312
355
  }
313
356
  const normalizedBundle = (product.product_bundle || []).map((item) => ({
314
357
  ...item,
@@ -324,7 +367,6 @@ function normalizeOrderProduct(product) {
324
367
  product_option_item: product.product_option_item || [],
325
368
  selling_price: resolvedSellingPrice,
326
369
  original_price: resolvedOriginalPrice,
327
- payment_price: product.payment_price || "0.00",
328
370
  tax_fee: product.tax_fee || "0.00",
329
371
  is_charge_tax: product.is_charge_tax ?? 0,
330
372
  discount_list: product.discount_list || [],
@@ -333,6 +375,69 @@ function normalizeOrderProduct(product) {
333
375
  _origin: product._origin
334
376
  };
335
377
  }
378
+ function collectLinkProductIdsFromReservationRules(rules) {
379
+ if (!Array.isArray(rules))
380
+ return [];
381
+ const ids = [];
382
+ for (const entry of rules) {
383
+ if (!entry || typeof entry !== "object")
384
+ continue;
385
+ const rec = entry;
386
+ if (rec.type !== "link")
387
+ continue;
388
+ if (!Array.isArray(rec.value))
389
+ continue;
390
+ for (const v of rec.value) {
391
+ const n = Number(v);
392
+ if (Number.isFinite(n) && n > 0)
393
+ ids.push(Math.floor(n));
394
+ }
395
+ }
396
+ return [...new Set(ids)];
397
+ }
398
+ function pickFirstDurationMinutesFromProducts(products) {
399
+ var _a;
400
+ for (const product of products) {
401
+ const value = (_a = product == null ? void 0 : product.duration) == null ? void 0 : _a.value;
402
+ const n = Number(value);
403
+ if (Number.isFinite(n) && n > 0)
404
+ return Math.floor(n);
405
+ }
406
+ return void 0;
407
+ }
408
+ function hasCustomCapacityProduct(products) {
409
+ return products.some((p) => {
410
+ var _a;
411
+ return ((_a = p == null ? void 0 : p.capacity) == null ? void 0 : _a.type) === "custom";
412
+ });
413
+ }
414
+ function pickFirstCustomCapacityPaxBounds(products) {
415
+ for (const p of products) {
416
+ const cap = p == null ? void 0 : p.capacity;
417
+ if (!cap || cap.type !== "custom")
418
+ continue;
419
+ if (!Array.isArray(cap.custom) || cap.custom.length === 0)
420
+ continue;
421
+ const row = cap.custom[0];
422
+ if (!row || typeof row !== "object")
423
+ continue;
424
+ const raw = row;
425
+ const out = {};
426
+ if (raw.min !== null && raw.min !== void 0 && raw.min !== "") {
427
+ const min = Number(raw.min);
428
+ if (Number.isFinite(min))
429
+ out.min = min;
430
+ }
431
+ if (raw.max !== null && raw.max !== void 0 && raw.max !== "") {
432
+ const max = Number(raw.max);
433
+ if (Number.isFinite(max))
434
+ out.max = max;
435
+ }
436
+ if (out.min !== void 0 || out.max !== void 0)
437
+ return out;
438
+ }
439
+ return void 0;
440
+ }
336
441
  // Annotate the CommonJS export names for ESM import in node:
337
442
  0 && (module.exports = {
338
443
  aggregateItemRuleLimit,
@@ -340,16 +445,20 @@ function normalizeOrderProduct(product) {
340
445
  buildItemRuleBusinessData,
341
446
  buildProductKey,
342
447
  buildQuantityLimitIndex,
448
+ collectLinkProductIdsFromReservationRules,
343
449
  createEmptySummary,
344
450
  extractStrategyModelIdsFromTableConfig,
345
451
  getProductIdentityIndex,
346
452
  getSafeProductNum,
347
453
  getTopLevelProductId,
348
454
  getTopLevelVariantId,
455
+ hasCustomCapacityProduct,
349
456
  isIdentityMatch,
350
457
  normalizeEnabledItemRuleIds,
351
458
  normalizeItemRuleStrategies,
352
459
  normalizeOrderProduct,
460
+ pickFirstCustomCapacityPaxBounds,
461
+ pickFirstDurationMinutesFromProducts,
353
462
  resolveSkuMatchedQuantityLimits,
354
463
  toBoolean,
355
464
  toNonNegativeInt,
@@ -25,6 +25,7 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
25
25
  private cacheId;
26
26
  private window;
27
27
  private request;
28
+ private baseSlotConfig;
28
29
  private itemRuleEvaluator;
29
30
  private itemRuleConfigs;
30
31
  private itemRuleConfigsPromise;
@@ -80,6 +81,9 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
80
81
  startDate: string;
81
82
  endDate: string;
82
83
  }): Promise<void>;
84
+ private getOperatingHoursScheduleIds;
85
+ private resolveSlotConfigForDate;
86
+ private syncOperatingHoursToSlotConfig;
83
87
  getDateRangeSummary(params: {
84
88
  startDate: string;
85
89
  endDate: string;
@@ -159,5 +163,15 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
159
163
  private refreshCartValidationPassed;
160
164
  setItemRuleRuntimeConfig(config?: VenueBookingItemRuleRuntimeConfig): Promise<void>;
161
165
  getOtherParams(): Record<string, any>;
166
+ private static readonly UI_STATE_KEY_PREFIX;
167
+ private getUIStateBucketKey;
168
+ private readUIStateBucket;
169
+ private writeUIStateBucket;
170
+ setUIState(key: string, value: any): void;
171
+ getUIState<T = any>(key: string): T | undefined;
172
+ deleteUIState(key: string): void;
162
173
  checkOpenDataAvailability(): Promise<OpenDataAvailabilityResult>;
174
+ setOtherParams(params: Record<string, any>, { cover }?: {
175
+ cover?: boolean;
176
+ }): Promise<void>;
163
177
  }
@@ -40,6 +40,7 @@ var import_types2 = require("../BookingByStep/types");
40
40
  var import_ProductList = require("../../modules/ProductList");
41
41
  var import_Date = require("../../modules/Date");
42
42
  var import_Schedule = require("../../modules/Schedule");
43
+ var import_utils2 = require("../../modules/Schedule/utils");
43
44
  var import_Quotation = require("../../modules/Quotation");
44
45
  var import_OpenData = require("../../modules/OpenData");
45
46
  var import_types3 = require("../../modules/Account/types");
@@ -49,7 +50,7 @@ var import_resource = require("./utils/resource");
49
50
  var import_timeSlot = require("./utils/timeSlot");
50
51
  var import_dateSummary = require("./utils/dateSummary");
51
52
  var import_slotMerge = require("./utils/slotMerge");
52
- var import_utils2 = require("../../modules/Order/utils");
53
+ var import_utils3 = require("../../modules/Order/utils");
53
54
  var import_Order = require("../../modules/Order");
54
55
  var import_types4 = require("../RegisterAndLogin/types");
55
56
  var import_decimal = __toESM(require("decimal.js"));
@@ -96,6 +97,7 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
96
97
  }
97
98
  };
98
99
  this.otherParams = {};
100
+ this.baseSlotConfig = { ...import_types.DEFAULT_SLOT_CONFIG };
99
101
  this.itemRuleEvaluator = new import_itemRule.ItemRuleEvaluator();
100
102
  this.itemRuleConfigs = [];
101
103
  this.itemRuleConfigsPromise = null;
@@ -292,7 +294,7 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
292
294
  }
293
295
  }
294
296
  async initialize(core, options = {}) {
295
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
297
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
296
298
  this.logMethodStart("initialize");
297
299
  this.core = core;
298
300
  this.initializeOptions = options || {};
@@ -301,10 +303,11 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
301
303
  this.store.status = "initializing";
302
304
  this.store.error = null;
303
305
  this.store.rawResourceData = [];
304
- this.store.slotConfig = {
306
+ this.baseSlotConfig = {
305
307
  ...import_types.DEFAULT_SLOT_CONFIG,
306
308
  ...((_b = options.otherParams) == null ? void 0 : _b.slotConfig) || {}
307
309
  };
310
+ this.store.slotConfig = { ...this.baseSlotConfig };
308
311
  this.otherParams = options.otherParams || {};
309
312
  this.cacheId = (_c = this.otherParams) == null ? void 0 : _c.cacheId;
310
313
  this.itemRuleRuntimeConfig = ((_d = this.otherParams) == null ? void 0 : _d.venueBookingItemRule) || ((_e = this.otherParams) == null ? void 0 : _e.itemRule) || {};
@@ -425,8 +428,10 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
425
428
  if (this.store.schedule) {
426
429
  await this.store.schedule.loadAllSchedule();
427
430
  this.injectScheduleResolverToQuotation();
431
+ (_k = this.store.quotation) == null ? void 0 : _k.loadQuotations({
432
+ channel: (_j = this.otherParams) == null ? void 0 : _j.channel
433
+ });
428
434
  }
429
- this.loadQuotations();
430
435
  await this.refreshItemRuleQuantityLimits();
431
436
  this.store.status = "ready";
432
437
  console.log("[VenueBooking] 初始化完成");
@@ -643,27 +648,87 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
643
648
  }
644
649
  }
645
650
  // ─── 日期概览 & 时间槽矩阵(纯计算,不发请求) ───
651
+ getOperatingHoursScheduleIds() {
652
+ var _a, _b;
653
+ const openData = this.otherParams.openData || ((_b = (_a = this.store.openData) == null ? void 0 : _a.getOpenData) == null ? void 0 : _b.call(_a)) || null;
654
+ const rawIds = openData == null ? void 0 : openData["availability.operating_hours"];
655
+ if (!Array.isArray(rawIds))
656
+ return [];
657
+ return [...new Set(
658
+ rawIds.map((id) => Number(id)).filter((id) => Number.isFinite(id) && id > 0).map((id) => Math.floor(id))
659
+ )];
660
+ }
661
+ resolveSlotConfigForDate(date) {
662
+ var _a;
663
+ const nextSlotConfig = { ...this.baseSlotConfig };
664
+ if (!date || !this.store.schedule)
665
+ return nextSlotConfig;
666
+ const operatingHoursScheduleIds = this.getOperatingHoursScheduleIds();
667
+ if (!operatingHoursScheduleIds.length)
668
+ return nextSlotConfig;
669
+ const scheduleList = this.store.schedule.getScheduleListByIds(
670
+ operatingHoursScheduleIds
671
+ );
672
+ if (!scheduleList.length)
673
+ return nextSlotConfig;
674
+ const timeRangeMap = (0, import_utils2.calcMinTimeMaxTimeBySchedules)(
675
+ scheduleList,
676
+ void 0,
677
+ date
678
+ );
679
+ let earliestStart = null;
680
+ let latestEnd = null;
681
+ for (const schedule of scheduleList) {
682
+ const dateRangeList = ((_a = timeRangeMap == null ? void 0 : timeRangeMap[schedule.id]) == null ? void 0 : _a.dateRangeFormat) || [];
683
+ for (const range of dateRangeList) {
684
+ const start = (0, import_dayjs.default)(range == null ? void 0 : range.start);
685
+ const end = (0, import_dayjs.default)(range == null ? void 0 : range.end);
686
+ if (!start.isValid() || !end.isValid())
687
+ continue;
688
+ if (!earliestStart || start.isBefore(earliestStart)) {
689
+ earliestStart = start;
690
+ }
691
+ if (!latestEnd || end.isAfter(latestEnd)) {
692
+ latestEnd = end;
693
+ }
694
+ }
695
+ }
696
+ if (!earliestStart || !latestEnd)
697
+ return nextSlotConfig;
698
+ return {
699
+ ...nextSlotConfig,
700
+ businessStartTime: earliestStart.format("HH:mm"),
701
+ businessEndTime: latestEnd.format("HH:mm")
702
+ };
703
+ }
704
+ syncOperatingHoursToSlotConfig(date) {
705
+ const resolvedSlotConfig = this.resolveSlotConfigForDate(date);
706
+ this.store.slotConfig = resolvedSlotConfig;
707
+ return resolvedSlotConfig;
708
+ }
646
709
  getDateRangeSummary(params) {
647
710
  return (0, import_dateSummary.buildDateRangeSummary)({
648
711
  startDate: params.startDate,
649
712
  endDate: params.endDate,
650
- config: this.store.slotConfig,
713
+ config: this.baseSlotConfig,
651
714
  rawResources: this.store.rawResourceData,
652
715
  resourceProductMap: this.resourceProductMap,
653
- quotationModule: this.store.quotation
716
+ quotationModule: this.store.quotation,
717
+ resolveConfig: (date) => this.resolveSlotConfigForDate(date)
654
718
  });
655
719
  }
656
720
  getTimeSlotGrid(date) {
721
+ const resolvedSlotConfig = this.syncOperatingHoursToSlotConfig(date);
657
722
  let quotationPriceMap;
658
723
  if (this.store.quotation) {
659
724
  const productIds = [...new Set([...this.resourceProductMap.values()].map((m) => m.productId))];
660
- const timeLabels = (0, import_timeSlot.generateTimeLabels)(this.store.slotConfig);
725
+ const timeLabels = (0, import_timeSlot.generateTimeLabels)(resolvedSlotConfig);
661
726
  const timePoints = timeLabels.map((label) => `${date} ${label}`);
662
727
  quotationPriceMap = this.store.quotation.buildProductPriceMap({ productIds, timePoints });
663
728
  }
664
729
  return (0, import_timeSlot.buildTimeSlotGrid)({
665
730
  date,
666
- config: this.store.slotConfig,
731
+ config: resolvedSlotConfig,
667
732
  rawResources: this.store.rawResourceData,
668
733
  resourceProductMap: this.resourceProductMap,
669
734
  quotationPriceMap
@@ -798,7 +863,7 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
798
863
  for (let i = 0; i < merged.length; i++) {
799
864
  const group = merged[i];
800
865
  const identityKey = (0, import_slotMerge.buildVenueIdentityKey)(resourceId, i);
801
- const bookingUuid = (0, import_utils2.createUuidV4)();
866
+ const bookingUuid = (0, import_utils3.createUuidV4)();
802
867
  const startMoment = (0, import_dayjs.default)(group.startTime, "YYYY-MM-DD HH:mm");
803
868
  const endMoment = (0, import_dayjs.default)(group.endTime, "YYYY-MM-DD HH:mm");
804
869
  const duration = endMoment.diff(startMoment, "minute");
@@ -811,7 +876,6 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
811
876
  num: 1,
812
877
  selling_price: group.totalPrice,
813
878
  original_price: group.totalPrice,
814
- payment_price: group.totalPrice,
815
879
  is_charge_tax: (venueProduct == null ? void 0 : venueProduct.is_charge_tax) ?? 0,
816
880
  metadata: {
817
881
  venue_booking: true,
@@ -890,10 +954,13 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
890
954
  }
891
955
  // ─── 配置 ───
892
956
  setSlotConfig(config) {
893
- this.store.slotConfig = {
894
- ...this.store.slotConfig,
957
+ this.baseSlotConfig = {
958
+ ...this.baseSlotConfig,
895
959
  ...config
896
960
  };
961
+ this.store.slotConfig = {
962
+ ...this.baseSlotConfig
963
+ };
897
964
  }
898
965
  getSlotConfig() {
899
966
  return { ...this.store.slotConfig };
@@ -984,7 +1051,7 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
984
1051
  const merged = (0, import_slotMerge.mergeConsecutiveSlots)(updatedSlots);
985
1052
  if (merged.length === 1) {
986
1053
  product.selling_price = merged[0].totalPrice;
987
- product.payment_price = merged[0].totalPrice;
1054
+ product.original_price = merged[0].totalPrice;
988
1055
  product.metadata.price_breakdown = (0, import_slotMerge.buildPriceBreakdown)({
989
1056
  group: merged[0],
990
1057
  productId: mapping.productId,
@@ -999,7 +1066,7 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
999
1066
  });
1000
1067
  if (quotationPrice !== null) {
1001
1068
  product.selling_price = quotationPrice;
1002
- product.payment_price = quotationPrice;
1069
+ product.original_price = quotationPrice;
1003
1070
  }
1004
1071
  }
1005
1072
  }
@@ -1094,15 +1161,14 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1094
1161
  return rid != null && selectedResourceIds.has(rid);
1095
1162
  });
1096
1163
  if (product.discount_list.length < before) {
1097
- const totalDiscountAmount = product.discount_list.reduce(
1164
+ const totalPerUnitDiscount = product.discount_list.reduce(
1098
1165
  (sum, pd) => sum + (pd.amount || 0),
1099
1166
  0
1100
1167
  );
1101
- const newPaymentPrice = new import_decimal.default(product.selling_price || 0).minus(totalDiscountAmount).toNumber();
1102
- const paymentStr = (0, import_utils.toPriceString)(newPaymentPrice);
1103
- product.payment_price = paymentStr;
1168
+ const newSellingPrice = new import_decimal.default(product.original_price || product.selling_price || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
1169
+ product.selling_price = newSellingPrice;
1104
1170
  if (product.metadata) {
1105
- product.metadata.main_product_selling_price = paymentStr;
1171
+ product.metadata.main_product_selling_price = newSellingPrice;
1106
1172
  }
1107
1173
  }
1108
1174
  }
@@ -1158,7 +1224,7 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1158
1224
  }
1159
1225
  }
1160
1226
  async submitOrder() {
1161
- var _a;
1227
+ var _a, _b, _c, _d, _e;
1162
1228
  this.logMethodStart("submitOrder");
1163
1229
  try {
1164
1230
  await this.validateBeforeSubmitByItemRule();
@@ -1166,11 +1232,15 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1166
1232
  throw new Error("venueBooking解决方案需要 order 模块支持");
1167
1233
  }
1168
1234
  const result = await this.store.order.submitTempOrder({
1169
- cacheId: this.cacheId
1235
+ cacheId: this.cacheId,
1236
+ platform: (_a = this.otherParams) == null ? void 0 : _a.platform,
1237
+ businessCode: (_b = this.otherParams) == null ? void 0 : _b.businessCode,
1238
+ channel: (_c = this.otherParams) == null ? void 0 : _c.channel,
1239
+ type: (_d = this.otherParams) == null ? void 0 : _d.type
1170
1240
  });
1171
1241
  const tempOrder = this.store.order.getTempOrder();
1172
1242
  this.logMethodSuccess("submitOrder", {
1173
- productCount: ((_a = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _a.length) || 0
1243
+ productCount: ((_e = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _e.length) || 0
1174
1244
  });
1175
1245
  return result;
1176
1246
  } catch (error) {
@@ -1195,10 +1265,9 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1195
1265
  });
1196
1266
  if (quotationPrice !== null) {
1197
1267
  product.selling_price = quotationPrice;
1198
- if (product.original_price == null) {
1199
- product.original_price = quotationPrice;
1200
- }
1201
- product.payment_price = quotationPrice;
1268
+ product.original_price = quotationPrice;
1269
+ } else if (product.selling_price != null) {
1270
+ product.original_price = product.selling_price;
1202
1271
  }
1203
1272
  }
1204
1273
  const products = await this.store.order.addProductToOrder(product);
@@ -1443,16 +1512,13 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1443
1512
  });
1444
1513
  if (productIndex === -1) {
1445
1514
  const sellingPrice = (0, import_utils.toPriceString)((sourceItem == null ? void 0 : sourceItem.price) ?? (sourceItem == null ? void 0 : sourceItem.selling_price), "0.00");
1446
- const originalPrice = (0, import_utils.toPriceString)((sourceItem == null ? void 0 : sourceItem.original_price) ?? (sourceItem == null ? void 0 : sourceItem.price) ?? sellingPrice, sellingPrice);
1447
- const paymentPrice = (0, import_utils.toPriceString)((sourceItem == null ? void 0 : sourceItem.payment_price) ?? (sourceItem == null ? void 0 : sourceItem.price) ?? sellingPrice, sellingPrice);
1448
1515
  tempOrder.products.push(
1449
1516
  (0, import_utils.normalizeOrderProduct)({
1450
1517
  product_id: productId,
1451
1518
  product_variant_id: productVariantId,
1452
1519
  num: targetQuantity,
1453
1520
  selling_price: sellingPrice,
1454
- original_price: originalPrice,
1455
- payment_price: paymentPrice,
1521
+ original_price: sellingPrice,
1456
1522
  metadata: { item_rule_prefill: true, item_rule_id: prefillItem.ruleId },
1457
1523
  _origin: { ...sourceItem || {}, item_rule_prefill: true, item_rule_id: prefillItem.ruleId }
1458
1524
  })
@@ -1561,6 +1627,53 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1561
1627
  getOtherParams() {
1562
1628
  return this.otherParams;
1563
1629
  }
1630
+ getUIStateBucketKey() {
1631
+ if (!this.cacheId)
1632
+ return null;
1633
+ return `${_VenueBookingImpl.UI_STATE_KEY_PREFIX}${this.cacheId}`;
1634
+ }
1635
+ readUIStateBucket() {
1636
+ var _a;
1637
+ const key = this.getUIStateBucketKey();
1638
+ if (!key || !((_a = this.window) == null ? void 0 : _a.sessionStorage))
1639
+ return {};
1640
+ try {
1641
+ const raw = this.window.sessionStorage.getItem(key) || "{}";
1642
+ const parsed = JSON.parse(raw);
1643
+ return parsed && typeof parsed === "object" ? parsed : {};
1644
+ } catch {
1645
+ return {};
1646
+ }
1647
+ }
1648
+ writeUIStateBucket(bucket) {
1649
+ var _a;
1650
+ const key = this.getUIStateBucketKey();
1651
+ if (!key || !((_a = this.window) == null ? void 0 : _a.sessionStorage))
1652
+ return;
1653
+ this.window.sessionStorage.setItem(key, JSON.stringify(bucket));
1654
+ }
1655
+ setUIState(key, value) {
1656
+ if (!this.getUIStateBucketKey())
1657
+ return;
1658
+ const bucket = this.readUIStateBucket();
1659
+ bucket[key] = value;
1660
+ this.writeUIStateBucket(bucket);
1661
+ }
1662
+ getUIState(key) {
1663
+ if (!this.getUIStateBucketKey())
1664
+ return void 0;
1665
+ const bucket = this.readUIStateBucket();
1666
+ return bucket[key];
1667
+ }
1668
+ deleteUIState(key) {
1669
+ if (!this.getUIStateBucketKey())
1670
+ return;
1671
+ const bucket = this.readUIStateBucket();
1672
+ if (key in bucket) {
1673
+ delete bucket[key];
1674
+ this.writeUIStateBucket(bucket);
1675
+ }
1676
+ }
1564
1677
  // ─── OpenData 可用性 ───
1565
1678
  async checkOpenDataAvailability() {
1566
1679
  if (!this.store.openData)
@@ -1568,9 +1681,22 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1568
1681
  await this.loadOpenDataConfig();
1569
1682
  return this.store.openData.checkAvailability(this.store.schedule);
1570
1683
  }
1684
+ async setOtherParams(params, { cover = false } = {}) {
1685
+ if (cover) {
1686
+ this.otherParams = params;
1687
+ } else {
1688
+ this.otherParams = { ...this.otherParams, ...params };
1689
+ }
1690
+ }
1571
1691
  };
1572
1692
  var VenueBookingImpl = _VenueBookingImpl;
1573
1693
  VenueBookingImpl.OPEN_DATA_CACHE_TTL = 5 * 60 * 1e3;
1694
+ // ─── UI 状态缓存(按 cacheId 分桶,sessionStorage) ───
1695
+ //
1696
+ // 用于物料层持久化 UI 层面的轻量状态(如当前步骤、登录回跳意图等)。
1697
+ // 桶键:pisell.venueBooking.uiState:<cacheId>;内部以 JSON object 形式存储多个字段。
1698
+ // 无 cacheId 时所有方法自动降级为 no-op,上层不用判空。
1699
+ VenueBookingImpl.UI_STATE_KEY_PREFIX = "pisell.venueBooking.uiState:";
1574
1700
  // Annotate the CommonJS export names for ESM import in node:
1575
1701
  0 && (module.exports = {
1576
1702
  VenueBookingImpl,
@@ -7,4 +7,5 @@ export declare function buildDateRangeSummary(params: {
7
7
  rawResources: VenueResourceRawData[];
8
8
  resourceProductMap: Map<number | string, ResourceProductMapping>;
9
9
  quotationModule?: QuotationModule;
10
+ resolveConfig?: (date: string) => VenueBookingSlotConfig;
10
11
  }): VenueDateSummaryItem[];
@@ -35,22 +35,31 @@ module.exports = __toCommonJS(dateSummary_exports);
35
35
  var import_dayjs = __toESM(require("dayjs"));
36
36
  var import_timeSlot = require("./timeSlot");
37
37
  function buildDateRangeSummary(params) {
38
- const { startDate, endDate, config, rawResources, resourceProductMap, quotationModule } = params;
38
+ const {
39
+ startDate,
40
+ endDate,
41
+ config,
42
+ rawResources,
43
+ resourceProductMap,
44
+ quotationModule,
45
+ resolveConfig
46
+ } = params;
39
47
  const result = [];
40
48
  const productIds = quotationModule ? [...new Set([...resourceProductMap.values()].map((m) => m.productId))] : [];
41
49
  let cursor = (0, import_dayjs.default)(startDate);
42
50
  const end = (0, import_dayjs.default)(endDate);
43
51
  while (!cursor.isAfter(end)) {
44
52
  const date = cursor.format("YYYY-MM-DD");
53
+ const effectiveConfig = (resolveConfig == null ? void 0 : resolveConfig(date)) || config;
45
54
  let quotationPriceMap;
46
55
  if (quotationModule && productIds.length) {
47
- const timeLabels = (0, import_timeSlot.generateTimeLabels)(config);
56
+ const timeLabels = (0, import_timeSlot.generateTimeLabels)(effectiveConfig);
48
57
  const timePoints = timeLabels.map((label) => `${date} ${label}`);
49
58
  quotationPriceMap = quotationModule.buildProductPriceMap({ productIds, timePoints });
50
59
  }
51
60
  const grid = (0, import_timeSlot.buildTimeSlotGrid)({
52
61
  date,
53
- config,
62
+ config: effectiveConfig,
54
63
  rawResources,
55
64
  resourceProductMap,
56
65
  quotationPriceMap
@@ -79,7 +88,7 @@ function buildDateRangeSummary(params) {
79
88
  status = "unavailable";
80
89
  } else if (availableSlots === 0) {
81
90
  status = "sold_out";
82
- } else if ((totalSlots - availableSlots) / totalSlots >= config.fewLeftThreshold) {
91
+ } else if ((totalSlots - availableSlots) / totalSlots >= effectiveConfig.fewLeftThreshold) {
83
92
  status = "few_left";
84
93
  } else {
85
94
  status = "available";