@pisell/pisellos 0.0.500 → 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 (57) 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 +42 -38
  11. package/dist/modules/Order/types.d.ts +4 -0
  12. package/dist/modules/Order/utils.d.ts +28 -0
  13. package/dist/modules/Order/utils.js +93 -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/lib/model/strategy/adapter/itemRule/adapter.d.ts +8 -0
  30. package/lib/model/strategy/adapter/itemRule/adapter.js +41 -2
  31. package/lib/model/strategy/adapter/itemRule/examples.d.ts +15 -0
  32. package/lib/model/strategy/adapter/itemRule/examples.js +47 -0
  33. package/lib/model/strategy/adapter/itemRule/index.d.ts +1 -1
  34. package/lib/model/strategy/adapter/itemRule/index.js +2 -0
  35. package/lib/model/strategy/adapter/itemRule/type.d.ts +20 -1
  36. package/lib/model/strategy/adapter/promotion/index.js +0 -49
  37. package/lib/modules/Order/index.d.ts +6 -0
  38. package/lib/modules/Order/index.js +20 -36
  39. package/lib/modules/Order/types.d.ts +4 -0
  40. package/lib/modules/Order/utils.d.ts +28 -0
  41. package/lib/modules/Order/utils.js +78 -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/package.json +1 -1
@@ -36,9 +36,10 @@ export interface ScanOrderOrderProduct extends ScanOrderOrderProductIdentity {
36
36
  order_detail_id: number | null;
37
37
  num: number;
38
38
  product_option_item: any[];
39
+ /** 券后单品单价(= 订单域实际成交单价)。未应用券时等同 original_price。 */
39
40
  selling_price: string;
41
+ /** 券前单品单价(= 店铺售价),不承载后台划线价语义。 */
40
42
  original_price: string;
41
- payment_price: string;
42
43
  tax_fee: string;
43
44
  is_charge_tax: number;
44
45
  discount_list: any[];
@@ -47,6 +48,11 @@ export interface ScanOrderOrderProduct extends ScanOrderOrderProductIdentity {
47
48
  _origin?: Record<string, any>;
48
49
  }
49
50
  export interface ScanOrderSubmitProduct extends Omit<ScanOrderOrderProduct, '_origin' | 'identity_key'> {
51
+ /**
52
+ * 出站兼容字段:SDK 内部不再消费 payment_price,
53
+ * 仅在提交后端时由 selling_price 派生,保持原有后端契约。
54
+ */
55
+ payment_price: string;
50
56
  }
51
57
  export interface ScanOrderSummary {
52
58
  product_quantity: number;
@@ -121,6 +127,7 @@ export interface ScanOrderTempOrder {
121
127
  holder: Record<string, any> | null;
122
128
  summary: ScanOrderSummary;
123
129
  metadata: Record<string, any>;
130
+ lastOrderInfo?: Record<string, any>;
124
131
  }
125
132
  export interface ScanOrderSubmitPayload extends Omit<ScanOrderTempOrder, 'platform' | 'products' | 'created_at' | 'summary' | 'surcharges'> {
126
133
  platform: 'H5' | 'PC';
@@ -132,6 +139,11 @@ export interface ScanOrderSubmitPayload extends Omit<ScanOrderTempOrder, 'platfo
132
139
  products: ScanOrderSubmitProduct[];
133
140
  }
134
141
  export type ScanOrderAvailabilityMode = 'idle' | 'shop_closed' | 'resource_block' | 'resource_busy' | 'additional_order_with_code' | 'additional_order';
142
+ export interface ScanOrderTableFormRecord {
143
+ policy?: string | null;
144
+ partyroom_booking?: string | null;
145
+ [key: string]: any;
146
+ }
135
147
  export interface ScanOrderAvailabilityInfo {
136
148
  mode: ScanOrderAvailabilityMode;
137
149
  order_id?: string;
@@ -139,8 +151,16 @@ export interface ScanOrderAvailabilityInfo {
139
151
  table_form_id?: string;
140
152
  deskmate_valid?: boolean;
141
153
  errorTips?: string;
154
+ /** `/order/dining/table/config` 返回的 `table_form_record` 原样透出 */
155
+ table_form_record?: ScanOrderTableFormRecord | null;
142
156
  policy?: string | null;
143
157
  partyroom_booking?: string | null;
158
+ /** 预约规则关联商品存在 custom 容量时,由 checkResourceAvailable 置为 1 */
159
+ requestEntryPax?: number;
160
+ /** 首个 `capacity.type === 'custom'` 商品里 `custom[0]` 的 min(人数下限) */
161
+ requestPaxMin?: number;
162
+ /** 首个 `capacity.type === 'custom'` 商品里 `custom[0]` 的 max(人数上限) */
163
+ requestPaxMax?: number;
144
164
  }
145
165
  export interface ScanOrderTableSnackConfig {
146
166
  snack?: boolean | number | string;
@@ -150,9 +170,6 @@ export interface ScanOrderOrderNumberPrefixConfig {
150
170
  table_order?: string;
151
171
  pos?: string;
152
172
  }
153
- export interface ScanOrderTableFormRecord {
154
- policy?: string | null;
155
- }
156
173
  export interface ScanOrderTableConfigApiData {
157
174
  table_max_number?: number | string | null;
158
175
  order_count?: number | string | null;
@@ -183,7 +200,6 @@ export interface ScanOrderResourceState extends ScanOrderAvailabilityInfo {
183
200
  isFull: boolean;
184
201
  orderNumberPrefix: ScanOrderOrderNumberPrefixConfig[];
185
202
  raw: ScanOrderTableConfigApiData | null;
186
- table_form_record?: ScanOrderTableFormRecord | null;
187
203
  }
188
204
  export interface ScanOrderState {
189
205
  entryContext: ScanOrderEntryContext | null;
@@ -201,6 +217,7 @@ export interface ScanOrderState {
201
217
  passed: boolean | null;
202
218
  failures: QuantityCheckResult[];
203
219
  };
220
+ entryPaxNumber: number | null;
204
221
  }
205
222
  export interface ScanOrderLoggerRuntimeConfig {
206
223
  provider?: ScanOrderLoggerProviderType;
@@ -1,6 +1,7 @@
1
1
  import { ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderSummary, ScanOrderTempOrder } from './types';
2
2
  import type { CartItemSummary, ItemRuleBusinessData, PaxInfo, QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
3
3
  import type { StrategyConfig } from '../../model/strategy/type';
4
+ import type { ProductData } from '../../modules/Product/types';
4
5
  /**
5
6
  * 构建金额全为 0 的空 summary。
6
7
  * 作为尚未计算金额时的兜底默认值,避免下游因 undefined 报错。
@@ -58,8 +59,15 @@ export declare function resolveSkuMatchedQuantityLimits(params: {
58
59
  export declare function aggregateItemRuleLimit(matchedLimits: QuantityLimitResult[]): {
59
60
  min: number | undefined;
60
61
  max: number | undefined;
62
+ remainingMax: number | undefined;
61
63
  exact: number | undefined;
62
64
  mustInclude: boolean;
65
+ validationMessage: string | undefined;
66
+ rawValidationMessage: string | Record<string, string> | undefined;
67
+ maxValidationMessage: string | undefined;
68
+ rawMaxValidationMessage: string | Record<string, string> | undefined;
69
+ minValidationMessage: string | undefined;
70
+ rawMinValidationMessage: string | Record<string, string> | undefined;
63
71
  } | null;
64
72
  export declare function buildItemRuleBusinessData(params: {
65
73
  tempOrder: ScanOrderTempOrder;
@@ -91,3 +99,21 @@ export declare function getProductIdentityIndex(products: ScanOrderOrderProduct[
91
99
  * - 保留 _origin 供后续业务流程(如促销规则)使用
92
100
  */
93
101
  export declare function normalizeOrderProduct(product: Partial<ScanOrderOrderProduct> & ScanOrderOrderProductIdentity): ScanOrderOrderProduct;
102
+ /**
103
+ * 从 reservation.enabled_reservation_rules 中收集 type=link 的商品 id。
104
+ */
105
+ export declare function collectLinkProductIdsFromReservationRules(rules: unknown): number[];
106
+ /**
107
+ * 返回列表中第一个带有效 duration.value(分钟)的商品时长。
108
+ */
109
+ export declare function pickFirstDurationMinutesFromProducts(products: ProductData[]): number | undefined;
110
+ /** 是否存在 capacity.type === 'custom' 的商品 */
111
+ export declare function hasCustomCapacityProduct(products: ProductData[]): boolean;
112
+ /**
113
+ * 在商品列表中找到第一个 `capacity.type === 'custom'` 的商品,取其 `custom` 数组第一项的 min/max。
114
+ * 仅返回有限数字字段;若均无法解析则返回 `undefined`。
115
+ */
116
+ export declare function pickFirstCustomCapacityPaxBounds(products: ProductData[]): {
117
+ min?: number;
118
+ max?: number;
119
+ } | undefined;
@@ -170,28 +170,22 @@ export function buildQuantityLimitIndex(limits) {
170
170
  try {
171
171
  for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
172
172
  var limit = _step2.value;
173
- var _iterator3 = _createForOfIteratorHelper(limit.targets || []),
174
- _step3;
175
- try {
176
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
177
- var target = _step3.value;
178
- var productId = Number(target.product_id);
179
- if (!Number.isFinite(productId) || productId <= 0) continue;
180
- var variantId = Number(target.product_variant_id);
181
- var hasVariant = Number.isFinite(variantId) && variantId > 0;
182
- if (hasVariant) {
183
- var exactKey = buildProductKey(productId, variantId);
184
- var _existed = exactLimitMap.get(exactKey) || [];
185
- exactLimitMap.set(exactKey, [].concat(_toConsumableArray(_existed), [limit]));
186
- continue;
187
- }
188
- var existed = productLimitMap.get(productId) || [];
189
- productLimitMap.set(productId, [].concat(_toConsumableArray(existed), [limit]));
190
- }
191
- } catch (err) {
192
- _iterator3.e(err);
193
- } finally {
194
- _iterator3.f();
173
+ var targets = limit.targets || [];
174
+ // 多目标规则(OR 组)只做购物车聚合校验,不下发到单品维度,
175
+ // 避免 UI 把「组内至少 1 份」误当作每款商品各自的 min,锁死减号按钮。
176
+ if (targets.length !== 1) continue;
177
+ var target = targets[0];
178
+ var productId = Number(target.product_id);
179
+ if (!Number.isFinite(productId) || productId <= 0) continue;
180
+ var variantId = Number(target.product_variant_id);
181
+ var hasVariant = Number.isFinite(variantId) && variantId > 0;
182
+ if (hasVariant) {
183
+ var exactKey = buildProductKey(productId, variantId);
184
+ var existed = exactLimitMap.get(exactKey) || [];
185
+ exactLimitMap.set(exactKey, [].concat(_toConsumableArray(existed), [limit]));
186
+ } else {
187
+ var _existed = productLimitMap.get(productId) || [];
188
+ productLimitMap.set(productId, [].concat(_toConsumableArray(_existed), [limit]));
195
189
  }
196
190
  }
197
191
  } catch (err) {
@@ -216,38 +210,84 @@ export function aggregateItemRuleLimit(matchedLimits) {
216
210
  if (!matchedLimits.length) return null;
217
211
  var min;
218
212
  var max;
213
+ var remainingMax;
219
214
  var exact;
220
215
  var mustInclude = false;
221
- var _iterator4 = _createForOfIteratorHelper(matchedLimits),
222
- _step4;
216
+
217
+ // 聚合 validationMessage 按 min / max 两个方向分别输出:
218
+ // - maxValidationMessage:触发"当前 max / remainingMax / exact"的那条规则的文案
219
+ // - minValidationMessage:触发"当前 min / exact"的那条规则的文案
220
+ // 各自再回退到其他带文案的规则(最后回退到第一条非空 validationMessage)。
221
+ // 前端可根据"加号/减号被拦"的方向取对应文案。
222
+ var maxSourceLimit;
223
+ var remainingMaxSourceLimit;
224
+ var exactSourceLimit;
225
+ var minSourceLimit;
226
+ var firstMessagedLimit;
227
+ var _iterator3 = _createForOfIteratorHelper(matchedLimits),
228
+ _step3;
223
229
  try {
224
- for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
225
- var limit = _step4.value;
230
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
231
+ var limit = _step3.value;
226
232
  if (typeof limit.requiredMin === 'number' && Number.isFinite(limit.requiredMin)) {
227
- min = min === undefined ? limit.requiredMin : Math.max(min, limit.requiredMin);
233
+ if (min === undefined || limit.requiredMin > min) {
234
+ min = limit.requiredMin;
235
+ minSourceLimit = limit;
236
+ }
228
237
  }
229
238
  if (typeof limit.requiredMax === 'number' && Number.isFinite(limit.requiredMax)) {
230
- max = max === undefined ? limit.requiredMax : Math.min(max, limit.requiredMax);
239
+ if (max === undefined || limit.requiredMax < max) {
240
+ max = limit.requiredMax;
241
+ maxSourceLimit = limit;
242
+ }
243
+ }
244
+ if (typeof limit.remainingMax === 'number' && Number.isFinite(limit.remainingMax)) {
245
+ if (remainingMax === undefined || limit.remainingMax < remainingMax) {
246
+ remainingMax = limit.remainingMax;
247
+ remainingMaxSourceLimit = limit;
248
+ }
231
249
  }
232
250
  if (typeof limit.requiredExact === 'number' && Number.isFinite(limit.requiredExact)) {
233
251
  exact = limit.requiredExact;
252
+ exactSourceLimit = limit;
234
253
  }
235
254
  mustInclude = mustInclude || Boolean(limit.mustInclude);
255
+ if (!firstMessagedLimit && limit.validationMessage) {
256
+ firstMessagedLimit = limit;
257
+ }
236
258
  }
237
259
  } catch (err) {
238
- _iterator4.e(err);
260
+ _iterator3.e(err);
239
261
  } finally {
240
- _iterator4.f();
262
+ _iterator3.f();
241
263
  }
242
264
  if (typeof exact === 'number' && Number.isFinite(exact)) {
243
265
  min = exact;
244
266
  max = exact;
245
267
  }
268
+ var maxMessageSource = maxSourceLimit || remainingMaxSourceLimit || exactSourceLimit || firstMessagedLimit;
269
+ var minMessageSource = minSourceLimit || exactSourceLimit || firstMessagedLimit;
270
+ var maxValidationMessage = maxMessageSource === null || maxMessageSource === void 0 ? void 0 : maxMessageSource.validationMessage;
271
+ var rawMaxValidationMessage = maxMessageSource === null || maxMessageSource === void 0 ? void 0 : maxMessageSource.rawValidationMessage;
272
+ var minValidationMessage = minMessageSource === null || minMessageSource === void 0 ? void 0 : minMessageSource.validationMessage;
273
+ var rawMinValidationMessage = minMessageSource === null || minMessageSource === void 0 ? void 0 : minMessageSource.rawValidationMessage;
274
+
275
+ // validationMessage / rawValidationMessage 保留为"最严格限制"的聚合文案,
276
+ // 便于旧消费者(只关心 max 侧)不破坏。优先 max → min。
277
+ var validationMessage = maxValidationMessage !== null && maxValidationMessage !== void 0 ? maxValidationMessage : minValidationMessage;
278
+ var rawValidationMessage = rawMaxValidationMessage !== null && rawMaxValidationMessage !== void 0 ? rawMaxValidationMessage : rawMinValidationMessage;
246
279
  return {
247
280
  min: min,
248
281
  max: max,
282
+ remainingMax: remainingMax,
249
283
  exact: exact,
250
- mustInclude: mustInclude
284
+ mustInclude: mustInclude,
285
+ validationMessage: validationMessage,
286
+ rawValidationMessage: rawValidationMessage,
287
+ maxValidationMessage: maxValidationMessage,
288
+ rawMaxValidationMessage: rawMaxValidationMessage,
289
+ minValidationMessage: minValidationMessage,
290
+ rawMinValidationMessage: rawMinValidationMessage
251
291
  };
252
292
  }
253
293
  export function buildItemRuleBusinessData(params) {
@@ -295,11 +335,11 @@ export function buildItemRuleBusinessData(params) {
295
335
  export function attachItemRuleLimitsToTopLevelProducts(productList, limits) {
296
336
  if (!Array.isArray(productList)) return productList;
297
337
  var limitIndex = buildQuantityLimitIndex(limits || []);
298
- var _iterator5 = _createForOfIteratorHelper(productList),
299
- _step5;
338
+ var _iterator4 = _createForOfIteratorHelper(productList),
339
+ _step4;
300
340
  try {
301
- for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
302
- var item = _step5.value;
341
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
342
+ var item = _step4.value;
303
343
  if (!item || _typeof(item) !== 'object') continue;
304
344
  var productItem = item;
305
345
  var productId = getTopLevelProductId(productItem);
@@ -318,9 +358,9 @@ export function attachItemRuleLimitsToTopLevelProducts(productList, limits) {
318
358
  }
319
359
  }
320
360
  } catch (err) {
321
- _iterator5.e(err);
361
+ _iterator4.e(err);
322
362
  } finally {
323
- _iterator5.f();
363
+ _iterator4.f();
324
364
  }
325
365
  return productList;
326
366
  }
@@ -358,8 +398,14 @@ export function normalizeOrderProduct(product) {
358
398
  if (product.identity_key && !metadata.unique_identification_number) {
359
399
  metadata.unique_identification_number = product.identity_key;
360
400
  }
361
- var resolvedOriginalPrice = product.original_price || '0.00';
401
+
402
+ // selling_price:券后成交单价;original_price:券前店铺售价。
403
+ // 初次加购时两者相等(入口层应保证 caller 传的 original_price == selling_price);
404
+ // 券应用后由 Rules 引擎只改动 selling_price,保留 original_price 以便还原 / 展示划线对比。
405
+ // 注意:这里 caller 若显式传入了 original_price(例如 Rules 回写或单测场景),要尊重该值,
406
+ // 让券后状态能正确通过再次 normalize。
362
407
  var resolvedSellingPrice = product.selling_price || '0.00';
408
+ var resolvedOriginalPrice = product.original_price || resolvedSellingPrice;
363
409
  if (metadata.main_product_original_price === undefined) {
364
410
  metadata.main_product_original_price = resolvedOriginalPrice;
365
411
  }
@@ -367,14 +413,14 @@ export function normalizeOrderProduct(product) {
367
413
  metadata.main_product_selling_price = resolvedSellingPrice;
368
414
  }
369
415
  if (metadata.source_product_price === undefined) {
370
- var _product$_origin$orig, _product$_origin;
371
- metadata.source_product_price = (_product$_origin$orig = (_product$_origin = product._origin) === null || _product$_origin === void 0 ? void 0 : _product$_origin.original_price) !== null && _product$_origin$orig !== void 0 ? _product$_origin$orig : resolvedOriginalPrice;
416
+ var _ref, _product$_origin$pric, _product$_origin, _product$_origin2;
417
+ metadata.source_product_price = (_ref = (_product$_origin$pric = (_product$_origin = product._origin) === null || _product$_origin === void 0 ? void 0 : _product$_origin.price) !== null && _product$_origin$pric !== void 0 ? _product$_origin$pric : (_product$_origin2 = product._origin) === null || _product$_origin2 === void 0 ? void 0 : _product$_origin2.base_price) !== null && _ref !== void 0 ? _ref : resolvedSellingPrice;
372
418
  }
373
419
  var normalizedBundle = (product.product_bundle || []).map(function (item) {
374
- var _ref, _item$bundle_selling_, _ref2, _ref3, _item$custom_price;
420
+ var _ref2, _item$bundle_selling_, _ref3, _ref4, _item$custom_price;
375
421
  return _objectSpread(_objectSpread({}, item), {}, {
376
- bundle_selling_price: (_ref = (_item$bundle_selling_ = item.bundle_selling_price) !== null && _item$bundle_selling_ !== void 0 ? _item$bundle_selling_ : item.price) !== null && _ref !== void 0 ? _ref : '0.00',
377
- custom_price: (_ref2 = (_ref3 = (_item$custom_price = item.custom_price) !== null && _item$custom_price !== void 0 ? _item$custom_price : item.bundle_selling_price) !== null && _ref3 !== void 0 ? _ref3 : item.price) !== null && _ref2 !== void 0 ? _ref2 : '0.00'
422
+ bundle_selling_price: (_ref2 = (_item$bundle_selling_ = item.bundle_selling_price) !== null && _item$bundle_selling_ !== void 0 ? _item$bundle_selling_ : item.price) !== null && _ref2 !== void 0 ? _ref2 : '0.00',
423
+ custom_price: (_ref3 = (_ref4 = (_item$custom_price = item.custom_price) !== null && _item$custom_price !== void 0 ? _item$custom_price : item.bundle_selling_price) !== null && _ref4 !== void 0 ? _ref4 : item.price) !== null && _ref3 !== void 0 ? _ref3 : '0.00'
378
424
  });
379
425
  });
380
426
  return {
@@ -386,7 +432,6 @@ export function normalizeOrderProduct(product) {
386
432
  product_option_item: product.product_option_item || [],
387
433
  selling_price: resolvedSellingPrice,
388
434
  original_price: resolvedOriginalPrice,
389
- payment_price: product.payment_price || '0.00',
390
435
  tax_fee: product.tax_fee || '0.00',
391
436
  is_charge_tax: (_product$is_charge_ta = product.is_charge_tax) !== null && _product$is_charge_ta !== void 0 ? _product$is_charge_ta : 0,
392
437
  discount_list: product.discount_list || [],
@@ -394,4 +439,106 @@ export function normalizeOrderProduct(product) {
394
439
  metadata: metadata,
395
440
  _origin: product._origin
396
441
  };
442
+ }
443
+
444
+ /**
445
+ * 从 reservation.enabled_reservation_rules 中收集 type=link 的商品 id。
446
+ */
447
+ export function collectLinkProductIdsFromReservationRules(rules) {
448
+ if (!Array.isArray(rules)) return [];
449
+ var ids = [];
450
+ var _iterator5 = _createForOfIteratorHelper(rules),
451
+ _step5;
452
+ try {
453
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
454
+ var entry = _step5.value;
455
+ if (!entry || _typeof(entry) !== 'object') continue;
456
+ var rec = entry;
457
+ if (rec.type !== 'link') continue;
458
+ if (!Array.isArray(rec.value)) continue;
459
+ var _iterator6 = _createForOfIteratorHelper(rec.value),
460
+ _step6;
461
+ try {
462
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
463
+ var v = _step6.value;
464
+ var n = Number(v);
465
+ if (Number.isFinite(n) && n > 0) ids.push(Math.floor(n));
466
+ }
467
+ } catch (err) {
468
+ _iterator6.e(err);
469
+ } finally {
470
+ _iterator6.f();
471
+ }
472
+ }
473
+ } catch (err) {
474
+ _iterator5.e(err);
475
+ } finally {
476
+ _iterator5.f();
477
+ }
478
+ return _toConsumableArray(new Set(ids));
479
+ }
480
+
481
+ /**
482
+ * 返回列表中第一个带有效 duration.value(分钟)的商品时长。
483
+ */
484
+ export function pickFirstDurationMinutesFromProducts(products) {
485
+ var _iterator7 = _createForOfIteratorHelper(products),
486
+ _step7;
487
+ try {
488
+ for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
489
+ var _product$duration;
490
+ var product = _step7.value;
491
+ var value = product === null || product === void 0 || (_product$duration = product.duration) === null || _product$duration === void 0 ? void 0 : _product$duration.value;
492
+ var n = Number(value);
493
+ if (Number.isFinite(n) && n > 0) return Math.floor(n);
494
+ }
495
+ } catch (err) {
496
+ _iterator7.e(err);
497
+ } finally {
498
+ _iterator7.f();
499
+ }
500
+ return undefined;
501
+ }
502
+
503
+ /** 是否存在 capacity.type === 'custom' 的商品 */
504
+ export function hasCustomCapacityProduct(products) {
505
+ return products.some(function (p) {
506
+ var _p$capacity;
507
+ return (p === null || p === void 0 || (_p$capacity = p.capacity) === null || _p$capacity === void 0 ? void 0 : _p$capacity.type) === 'custom';
508
+ });
509
+ }
510
+
511
+ /**
512
+ * 在商品列表中找到第一个 `capacity.type === 'custom'` 的商品,取其 `custom` 数组第一项的 min/max。
513
+ * 仅返回有限数字字段;若均无法解析则返回 `undefined`。
514
+ */
515
+ export function pickFirstCustomCapacityPaxBounds(products) {
516
+ var _iterator8 = _createForOfIteratorHelper(products),
517
+ _step8;
518
+ try {
519
+ for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
520
+ var p = _step8.value;
521
+ var cap = p === null || p === void 0 ? void 0 : p.capacity;
522
+ if (!cap || cap.type !== 'custom') continue;
523
+ if (!Array.isArray(cap.custom) || cap.custom.length === 0) continue;
524
+ var row = cap.custom[0];
525
+ if (!row || _typeof(row) !== 'object') continue;
526
+ var raw = row;
527
+ var out = {};
528
+ if (raw.min !== null && raw.min !== undefined && raw.min !== '') {
529
+ var min = Number(raw.min);
530
+ if (Number.isFinite(min)) out.min = min;
531
+ }
532
+ if (raw.max !== null && raw.max !== undefined && raw.max !== '') {
533
+ var max = Number(raw.max);
534
+ if (Number.isFinite(max)) out.max = max;
535
+ }
536
+ if (out.min !== undefined || out.max !== undefined) return out;
537
+ }
538
+ } catch (err) {
539
+ _iterator8.e(err);
540
+ } finally {
541
+ _iterator8.f();
542
+ }
543
+ return undefined;
397
544
  }
@@ -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
  }