@pisell/pisellos 2.2.313 → 2.2.315

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +3 -1
  3. package/dist/model/strategy/adapter/itemRule/adapter.d.ts +3 -1
  4. package/dist/model/strategy/adapter/itemRule/adapter.js +74 -7
  5. package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +3 -1
  6. package/dist/model/strategy/adapter/itemRule/evaluator.js +13 -0
  7. package/dist/model/strategy/adapter/itemRule/type.d.ts +40 -1
  8. package/dist/model/strategy/adapter/itemRule/type.js +10 -0
  9. package/dist/modules/BookingContext/utils/productExtend.d.ts +7 -0
  10. package/dist/modules/BookingContext/utils/productExtend.js +62 -18
  11. package/dist/modules/BookingContext/utils/resources.js +1 -1
  12. package/dist/modules/BusinessAvailability/index.d.ts +30 -0
  13. package/dist/modules/BusinessAvailability/index.js +204 -0
  14. package/dist/modules/Cart/index.js +4 -3
  15. package/dist/modules/Cart/types.d.ts +2 -0
  16. package/dist/modules/Cart/utils/cartProduct.d.ts +3 -1
  17. package/dist/modules/Cart/utils/cartProduct.js +59 -32
  18. package/dist/modules/FulfillmentTiming/index.d.ts +11 -0
  19. package/dist/modules/FulfillmentTiming/index.js +407 -0
  20. package/dist/modules/FulfillmentTiming/types.d.ts +67 -0
  21. package/dist/modules/FulfillmentTiming/types.js +1 -0
  22. package/dist/modules/OpenData/types.d.ts +14 -0
  23. package/dist/modules/Order/index.d.ts +14 -2
  24. package/dist/modules/Order/index.js +856 -486
  25. package/dist/modules/Order/localEftposState.d.ts +13 -0
  26. package/dist/modules/Order/localEftposState.js +39 -0
  27. package/dist/modules/Order/pickupTiming.d.ts +46 -0
  28. package/dist/modules/Order/pickupTiming.js +53 -0
  29. package/dist/modules/Order/types.d.ts +30 -2
  30. package/dist/modules/Order/utils.js +25 -7
  31. package/dist/modules/Payment/index.js +9 -10
  32. package/dist/modules/Product/types.d.ts +11 -0
  33. package/dist/modules/ProductList/index.js +1 -1
  34. package/dist/modules/ResourcePlanner/planner.d.ts +2 -0
  35. package/dist/modules/ResourcePlanner/planner.js +332 -23
  36. package/dist/modules/ResourcePlanner/types.d.ts +29 -0
  37. package/dist/modules/Schedule/index.d.ts +8 -0
  38. package/dist/modules/Schedule/index.js +141 -39
  39. package/dist/modules/index.d.ts +1 -0
  40. package/dist/modules/index.js +1 -0
  41. package/dist/plugins/request.d.ts +7 -0
  42. package/dist/server/index.d.ts +1 -0
  43. package/dist/server/index.js +1536 -1309
  44. package/dist/server/modules/form/index.d.ts +19 -0
  45. package/dist/server/modules/form/index.js +205 -0
  46. package/dist/server/modules/form/types.d.ts +13 -0
  47. package/dist/server/modules/form/types.js +3 -0
  48. package/dist/server/modules/index.d.ts +3 -0
  49. package/dist/server/modules/index.js +4 -0
  50. package/dist/server/modules/order/index.d.ts +15 -0
  51. package/dist/server/modules/order/index.js +920 -688
  52. package/dist/server/modules/order/types.d.ts +1 -0
  53. package/dist/server/test.json +1 -1
  54. package/dist/server/utils/small-ticket.d.ts +1 -85
  55. package/dist/server/utils/small-ticket.js +2 -2542
  56. package/dist/shared/payment/loadPaymentMethods.d.ts +9 -0
  57. package/dist/shared/payment/loadPaymentMethods.js +66 -0
  58. package/dist/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
  59. package/dist/shared/receipt/customerInvoiceLanguages.js +60 -0
  60. package/dist/shared/receipt/loadCustomerInvoiceLayout.d.ts +27 -0
  61. package/dist/shared/receipt/loadCustomerInvoiceLayout.js +184 -0
  62. package/dist/shared/receipt/small-ticket.d.ts +96 -0
  63. package/dist/shared/receipt/small-ticket.js +2751 -0
  64. package/dist/shared/receipt/templateVisibility.d.ts +23 -0
  65. package/dist/shared/receipt/templateVisibility.js +64 -0
  66. package/dist/shared/sales/loadSalesOrderSnapshot.d.ts +9 -0
  67. package/dist/shared/sales/loadSalesOrderSnapshot.js +21 -0
  68. package/dist/solution/BaseSales/fulfillmentItemRules.d.ts +27 -0
  69. package/dist/solution/BaseSales/fulfillmentItemRules.js +750 -0
  70. package/dist/solution/BaseSales/index.d.ts +39 -16
  71. package/dist/solution/BaseSales/index.js +1754 -1154
  72. package/dist/solution/BaseSales/pickupTiming.d.ts +47 -0
  73. package/dist/solution/BaseSales/pickupTiming.js +616 -0
  74. package/dist/solution/BaseSales/types.d.ts +11 -0
  75. package/dist/solution/BaseSales/utils/parseSalesResponse.js +3 -0
  76. package/dist/solution/BookingByStep/index.d.ts +4 -2
  77. package/dist/solution/BookingByStep/index.js +8 -3
  78. package/dist/solution/BookingTicket/index.d.ts +8 -2
  79. package/dist/solution/BookingTicket/index.js +513 -436
  80. package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
  81. package/dist/solution/BookingTicket/utils/addProductDecision.js +1 -1
  82. package/dist/solution/BookingTicket/utils/cartView.js +3 -1
  83. package/dist/solution/OrderInvoicePreview/index.d.ts +66 -0
  84. package/dist/solution/OrderInvoicePreview/index.js +340 -0
  85. package/dist/solution/RegisterAndLogin/config.js +54 -11
  86. package/dist/solution/RegisterAndLogin/index.d.ts +2 -0
  87. package/dist/solution/RegisterAndLogin/index.js +1 -1
  88. package/dist/solution/RegisterAndLogin/utils.d.ts +12 -4
  89. package/dist/solution/RegisterAndLogin/utils.js +36 -16
  90. package/dist/solution/Sales/index.js +1 -1
  91. package/dist/solution/UnifiedBookingSales/businessAvailability.d.ts +27 -0
  92. package/dist/solution/UnifiedBookingSales/businessAvailability.js +292 -0
  93. package/dist/solution/UnifiedBookingSales/index.d.ts +36 -4
  94. package/dist/solution/UnifiedBookingSales/index.js +1714 -905
  95. package/dist/solution/UnifiedBookingSales/types.d.ts +16 -2
  96. package/dist/solution/VenueBooking/index.d.ts +15 -2
  97. package/dist/solution/VenueBooking/index.js +1062 -785
  98. package/dist/solution/VenueBooking/types.d.ts +2 -1
  99. package/dist/solution/VenueBooking/types.js +1 -0
  100. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  101. package/dist/solution/VenueBooking/utils/dateSummary.js +7 -4
  102. package/dist/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
  103. package/dist/solution/VenueBooking/utils/smartPricing.js +273 -0
  104. package/dist/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
  105. package/dist/solution/VenueBooking/utils/timeSlot.js +6 -3
  106. package/dist/solution/index.d.ts +1 -0
  107. package/dist/solution/index.js +2 -1
  108. package/lib/index.d.ts +2 -0
  109. package/lib/index.js +21 -1
  110. package/lib/model/strategy/adapter/itemRule/adapter.d.ts +3 -1
  111. package/lib/model/strategy/adapter/itemRule/adapter.js +54 -4
  112. package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +3 -1
  113. package/lib/model/strategy/adapter/itemRule/evaluator.js +9 -0
  114. package/lib/model/strategy/adapter/itemRule/type.d.ts +40 -1
  115. package/lib/model/strategy/adapter/itemRule/type.js +10 -0
  116. package/lib/modules/BookingContext/utils/productExtend.d.ts +7 -0
  117. package/lib/modules/BookingContext/utils/productExtend.js +45 -2
  118. package/lib/modules/BookingContext/utils/resources.js +1 -1
  119. package/lib/modules/BusinessAvailability/index.d.ts +30 -0
  120. package/lib/modules/BusinessAvailability/index.js +146 -0
  121. package/lib/modules/Cart/index.js +4 -2
  122. package/lib/modules/Cart/types.d.ts +2 -0
  123. package/lib/modules/Cart/utils/cartProduct.d.ts +3 -1
  124. package/lib/modules/Cart/utils/cartProduct.js +39 -20
  125. package/lib/modules/FulfillmentTiming/index.d.ts +11 -0
  126. package/lib/modules/FulfillmentTiming/index.js +359 -0
  127. package/lib/modules/FulfillmentTiming/types.d.ts +67 -0
  128. package/lib/modules/FulfillmentTiming/types.js +5 -0
  129. package/lib/modules/OpenData/types.d.ts +14 -0
  130. package/lib/modules/Order/index.d.ts +14 -2
  131. package/lib/modules/Order/index.js +240 -38
  132. package/lib/modules/Order/localEftposState.d.ts +13 -0
  133. package/lib/modules/Order/localEftposState.js +44 -0
  134. package/lib/modules/Order/pickupTiming.d.ts +46 -0
  135. package/lib/modules/Order/pickupTiming.js +61 -0
  136. package/lib/modules/Order/types.d.ts +30 -2
  137. package/lib/modules/Order/utils.js +21 -5
  138. package/lib/modules/Payment/index.js +3 -4
  139. package/lib/modules/Product/types.d.ts +11 -0
  140. package/lib/modules/ProductList/index.js +1 -1
  141. package/lib/modules/ResourcePlanner/planner.d.ts +2 -0
  142. package/lib/modules/ResourcePlanner/planner.js +252 -8
  143. package/lib/modules/ResourcePlanner/types.d.ts +29 -0
  144. package/lib/modules/Schedule/index.d.ts +8 -0
  145. package/lib/modules/Schedule/index.js +68 -12
  146. package/lib/modules/index.d.ts +1 -0
  147. package/lib/modules/index.js +11 -0
  148. package/lib/plugins/request.d.ts +7 -0
  149. package/lib/server/index.d.ts +1 -0
  150. package/lib/server/index.js +158 -37
  151. package/lib/server/modules/form/index.d.ts +19 -0
  152. package/lib/server/modules/form/index.js +73 -0
  153. package/lib/server/modules/form/types.d.ts +13 -0
  154. package/lib/server/modules/form/types.js +9 -0
  155. package/lib/server/modules/index.d.ts +3 -0
  156. package/lib/server/modules/index.js +15 -1
  157. package/lib/server/modules/order/index.d.ts +15 -0
  158. package/lib/server/modules/order/index.js +114 -3
  159. package/lib/server/modules/order/types.d.ts +1 -0
  160. package/lib/server/test.json +1 -1
  161. package/lib/server/utils/small-ticket.d.ts +1 -85
  162. package/lib/server/utils/small-ticket.js +9 -2305
  163. package/lib/shared/payment/loadPaymentMethods.d.ts +9 -0
  164. package/lib/shared/payment/loadPaymentMethods.js +40 -0
  165. package/lib/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
  166. package/lib/shared/receipt/customerInvoiceLanguages.js +58 -0
  167. package/lib/shared/receipt/loadCustomerInvoiceLayout.d.ts +27 -0
  168. package/lib/shared/receipt/loadCustomerInvoiceLayout.js +124 -0
  169. package/lib/shared/receipt/small-ticket.d.ts +96 -0
  170. package/lib/shared/receipt/small-ticket.js +2546 -0
  171. package/lib/shared/receipt/templateVisibility.d.ts +23 -0
  172. package/lib/shared/receipt/templateVisibility.js +63 -0
  173. package/lib/shared/sales/loadSalesOrderSnapshot.d.ts +9 -0
  174. package/lib/shared/sales/loadSalesOrderSnapshot.js +22 -0
  175. package/lib/solution/BaseSales/fulfillmentItemRules.d.ts +27 -0
  176. package/lib/solution/BaseSales/fulfillmentItemRules.js +259 -0
  177. package/lib/solution/BaseSales/index.d.ts +39 -16
  178. package/lib/solution/BaseSales/index.js +333 -31
  179. package/lib/solution/BaseSales/pickupTiming.d.ts +47 -0
  180. package/lib/solution/BaseSales/pickupTiming.js +290 -0
  181. package/lib/solution/BaseSales/types.d.ts +11 -0
  182. package/lib/solution/BaseSales/utils/parseSalesResponse.js +3 -0
  183. package/lib/solution/BookingByStep/index.d.ts +4 -2
  184. package/lib/solution/BookingByStep/index.js +7 -3
  185. package/lib/solution/BookingTicket/index.d.ts +8 -2
  186. package/lib/solution/BookingTicket/index.js +65 -6
  187. package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
  188. package/lib/solution/BookingTicket/utils/addProductDecision.js +1 -1
  189. package/lib/solution/BookingTicket/utils/cartView.js +3 -1
  190. package/lib/solution/OrderInvoicePreview/index.d.ts +66 -0
  191. package/lib/solution/OrderInvoicePreview/index.js +246 -0
  192. package/lib/solution/RegisterAndLogin/config.js +57 -11
  193. package/lib/solution/RegisterAndLogin/index.d.ts +2 -0
  194. package/lib/solution/RegisterAndLogin/index.js +9 -1
  195. package/lib/solution/RegisterAndLogin/utils.d.ts +12 -4
  196. package/lib/solution/RegisterAndLogin/utils.js +24 -17
  197. package/lib/solution/Sales/index.js +1 -1
  198. package/lib/solution/UnifiedBookingSales/businessAvailability.d.ts +27 -0
  199. package/lib/solution/UnifiedBookingSales/businessAvailability.js +138 -0
  200. package/lib/solution/UnifiedBookingSales/index.d.ts +36 -4
  201. package/lib/solution/UnifiedBookingSales/index.js +561 -74
  202. package/lib/solution/UnifiedBookingSales/types.d.ts +16 -2
  203. package/lib/solution/VenueBooking/index.d.ts +15 -2
  204. package/lib/solution/VenueBooking/index.js +243 -96
  205. package/lib/solution/VenueBooking/types.d.ts +2 -1
  206. package/lib/solution/VenueBooking/types.js +1 -0
  207. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  208. package/lib/solution/VenueBooking/utils/dateSummary.js +7 -4
  209. package/lib/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
  210. package/lib/solution/VenueBooking/utils/smartPricing.js +224 -0
  211. package/lib/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
  212. package/lib/solution/VenueBooking/utils/timeSlot.js +5 -2
  213. package/lib/solution/index.d.ts +1 -0
  214. package/lib/solution/index.js +11 -0
  215. package/package.json +1 -1
@@ -1,4 +1,8 @@
1
1
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
3
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
4
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
5
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
2
6
  function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
3
7
  function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
4
8
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
@@ -171,7 +175,11 @@ function resolveCutOffPolicyIssue(policy) {
171
175
  return null;
172
176
  }
173
177
  function addLeadWindow(base, unit, unitType, _timezoneName) {
174
- if (unitType === 'days') return addLocalCalendarDays(base, unit);
178
+ if (unitType === 'days') {
179
+ var leadDate = addLocalCalendarDays(base, unit);
180
+ // Positive day lead times start at midnight; zero days keeps the current-time boundary.
181
+ return Math.trunc(unit) > 0 ? localDateToScalarStart(formatLocalDate(leadDate)) : leadDate;
182
+ }
175
183
  if (unitType === 'hours') return addLocalHours(base, unit);
176
184
  return addLocalMinutes(base, unit);
177
185
  }
@@ -263,6 +271,18 @@ function evaluateCandidateTimeGate(params) {
263
271
  };
264
272
  }
265
273
  var policy = product.cutOffPolicy;
274
+ // Current duration items can be shown outside business hours. Their real
275
+ // interval must remain unavailable, including products with no resource groups.
276
+ if (evaluationContext.useDurationTimeGrid && product.kind === 'duration' && !projection.meta.defaults.operatingHours.windows.some(function (window) {
277
+ var range = normalizeAbsoluteRange(window);
278
+ return range && contains(range, candidateRange);
279
+ })) {
280
+ return {
281
+ status: 'unavailable',
282
+ reasonCodes: ['outside_operating_hours'],
283
+ conflictCode: 'booking_cutoff'
284
+ };
285
+ }
266
286
  if (!policy) return null;
267
287
  if (resolveCutOffPolicyIssue(policy)) {
268
288
  return {
@@ -299,8 +319,8 @@ function evaluateCandidateTimeGate(params) {
299
319
  // otherwise a minute refresh turns it into 0 capacity and incorrectly
300
320
  // advances a create flow to the next slot. The earlier `past` gate still
301
321
  // rejects the anchor once its booking range has ended.
302
- var isActivePosDurationAnchor = evaluationContext.useExactDurationCandidateMinute && product.kind === 'duration' && !product.isFlexibleDuration && evaluationContext.durationCandidateAnchorAtMs === candidateRange.start;
303
- var usesMinutePrecision = product.isFlexibleDuration || evaluationContext.useExactDurationCandidateMinute && product.kind === 'duration';
322
+ var isActivePosDurationAnchor = evaluationContext.useExactDurationCandidateMinute && !evaluationContext.enforceSaleCutoff && product.kind === 'duration' && !product.isFlexibleDuration && evaluationContext.durationCandidateAnchorAtMs === candidateRange.start;
323
+ var usesMinutePrecision = product.isFlexibleDuration || evaluationContext.useDurationTimeGrid || evaluationContext.useExactDurationCandidateMinute && product.kind === 'duration';
304
324
  var hasNotReachedStart = isActivePosDurationAnchor || (usesMinutePrecision ? floorToMinute(now) <= candidateRange.start : now < candidateRange.start);
305
325
  if (hasNotReachedStart) return null;
306
326
  return {
@@ -494,7 +514,7 @@ function normalizeResources(resources) {
494
514
  });
495
515
  }
496
516
  function normalizeOperatingHours(params) {
497
- var _params$input, _params$input2, _params$input3, _params$input4;
517
+ var _params$input, _params$input2, _params$input3, _params$input4, _params$input5, _params$input6;
498
518
  var fallbackWindows = enumerateDates(params.dateRange.startDate, params.dateRange.endDate).map(function (date) {
499
519
  var start = toDateTimeInDate(date, params.businessHours.startTime, params.timezoneName);
500
520
  var end = toDateTimeInDate(date, params.businessHours.endTime, params.timezoneName);
@@ -530,11 +550,43 @@ function normalizeOperatingHours(params) {
530
550
  };
531
551
  var windows = normalizeWindows(sourceWindows);
532
552
  var excludedWindows = normalizeWindows(((_params$input = params.input) === null || _params$input === void 0 ? void 0 : _params$input.excludedWindows) || []);
553
+ // Keep original dates and opening anchors separately: the availability
554
+ // windows below may be clipped at midnight or merged without segment identity.
555
+ var periodMap = new Map();
556
+ var originalPeriods = ((_params$input2 = params.input) === null || _params$input2 === void 0 ? void 0 : _params$input2.businessPeriods) || [].concat(_toConsumableArray(sourceWindows), _toConsumableArray(((_params$input3 = params.input) === null || _params$input3 === void 0 ? void 0 : _params$input3.excludedWindows) || [])).map(function (window) {
557
+ return {
558
+ businessDate: window.businessDate || window.startAt.slice(0, 10),
559
+ startAt: window.openingAnchorAt || window.startAt,
560
+ endAt: window.endAt
561
+ };
562
+ });
563
+ originalPeriods.forEach(function (period) {
564
+ var range = normalizeAbsoluteRange(period);
565
+ if (!range) return;
566
+ var previous = periodMap.get(period.businessDate);
567
+ periodMap.set(period.businessDate, {
568
+ start: previous ? Math.min(previous.start, range.start) : range.start,
569
+ end: previous ? Math.max(previous.end, range.end) : range.end
570
+ });
571
+ });
572
+ var businessPeriods = Array.from(periodMap, function (_ref) {
573
+ var _ref2 = _slicedToArray(_ref, 2),
574
+ businessDate = _ref2[0],
575
+ range = _ref2[1];
576
+ return {
577
+ businessDate: businessDate,
578
+ startAt: formatDateTime(range.start, params.timezoneName, params.fixedOffsetMinutes),
579
+ endAt: formatDateTime(range.end, params.timezoneName, params.fixedOffsetMinutes)
580
+ };
581
+ }).sort(function (left, right) {
582
+ return left.startAt.localeCompare(right.startAt);
583
+ });
533
584
  return _objectSpread({
534
- source: ((_params$input2 = params.input) === null || _params$input2 === void 0 ? void 0 : _params$input2.source) || params.fallbackSource,
535
- scheduleIds: uniqById(((_params$input3 = params.input) === null || _params$input3 === void 0 ? void 0 : _params$input3.scheduleIds) || []),
536
- missingScheduleIds: uniqById(((_params$input4 = params.input) === null || _params$input4 === void 0 ? void 0 : _params$input4.missingScheduleIds) || []),
537
- windows: windows
585
+ source: ((_params$input4 = params.input) === null || _params$input4 === void 0 ? void 0 : _params$input4.source) || params.fallbackSource,
586
+ scheduleIds: uniqById(((_params$input5 = params.input) === null || _params$input5 === void 0 ? void 0 : _params$input5.scheduleIds) || []),
587
+ missingScheduleIds: uniqById(((_params$input6 = params.input) === null || _params$input6 === void 0 ? void 0 : _params$input6.missingScheduleIds) || []),
588
+ windows: windows,
589
+ businessPeriods: businessPeriods
538
590
  }, excludedWindows.length > 0 ? {
539
591
  excludedWindows: excludedWindows
540
592
  } : {});
@@ -553,8 +605,8 @@ function matchesRequirementGroup(requirementGroup, resource, product) {
553
605
  return resource.capacity >= resolveRequiredCapacity(requirementGroup, product, partySize);
554
606
  }
555
607
  function resolveRequiredCapacity(requirementGroup, product, partySize) {
556
- var _ref, _ref2;
557
- return Math.max(1, Number((_ref = (_ref2 = partySize !== null && partySize !== void 0 ? partySize : requirementGroup.capacityRequired) !== null && _ref2 !== void 0 ? _ref2 : product.capacityRequired) !== null && _ref !== void 0 ? _ref : 1) || 1);
608
+ var _ref3, _ref4;
609
+ return Math.max(1, Number((_ref3 = (_ref4 = partySize !== null && partySize !== void 0 ? partySize : requirementGroup.capacityRequired) !== null && _ref4 !== void 0 ? _ref4 : product.capacityRequired) !== null && _ref3 !== void 0 ? _ref3 : 1) || 1);
558
610
  }
559
611
  function buildCellKey(params) {
560
612
  return [String(params.productId), params.groupId, String(params.resourceId), params.start, params.end].join(':');
@@ -608,8 +660,8 @@ function buildCells(projection) {
608
660
  boundaries.add(window.start);
609
661
  boundaries.add(window.end);
610
662
  });
611
- occupancies.forEach(function (_ref3) {
612
- var range = _ref3.range;
663
+ occupancies.forEach(function (_ref5) {
664
+ var range = _ref5.range;
613
665
  boundaries.add(range.start);
614
666
  boundaries.add(range.end);
615
667
  });
@@ -627,11 +679,11 @@ function buildCells(projection) {
627
679
  var isInsideWorkingWindow = windows.some(function (window) {
628
680
  return contains(window, segment);
629
681
  });
630
- var segmentOccupancies = isInsideWorkingWindow ? occupancies.filter(function (_ref4) {
631
- var range = _ref4.range;
682
+ var segmentOccupancies = isInsideWorkingWindow ? occupancies.filter(function (_ref6) {
683
+ var range = _ref6.range;
632
684
  return overlaps(range, segment);
633
- }).map(function (_ref5) {
634
- var occupancy = _ref5.occupancy;
685
+ }).map(function (_ref7) {
686
+ var occupancy = _ref7.occupancy;
635
687
  return occupancy;
636
688
  }) : [];
637
689
  var usedCapacity = segmentOccupancies.reduce(function (sum, occupancy) {
@@ -1108,6 +1160,211 @@ function createDurationTimeRangeWithEnd(product, start, bookingEnd, projection,
1108
1160
  scheduleRefs: []
1109
1161
  };
1110
1162
  }
1163
+
1164
+ /** Resolve the label without changing the real calendar timestamp. */
1165
+ export function getDurationBusinessDate(projection, startAt) {
1166
+ var start = toDateTime(startAt);
1167
+ var periods = projection.meta.defaults.operatingHours.businessPeriods || [];
1168
+ var period = _toConsumableArray(periods).reverse().find(function (item) {
1169
+ var range = normalizeAbsoluteRange(item);
1170
+ return range && range.start <= start && start < range.end;
1171
+ });
1172
+ return (period === null || period === void 0 ? void 0 : period.businessDate) || startAt.slice(0, 10);
1173
+ }
1174
+ function getAlignedDurationRanges(params) {
1175
+ var _request$rememberedSt, _request$editingStart;
1176
+ var projection = params.projection,
1177
+ product = params.product,
1178
+ request = params.request,
1179
+ runtimeOptions = params.runtimeOptions,
1180
+ dateRange = params.dateRange,
1181
+ operatingRanges = params.operatingRanges,
1182
+ baseRanges = params.baseRanges,
1183
+ resourceWindowIndex = params.resourceWindowIndex,
1184
+ fixedOffsetMinutes = params.fixedOffsetMinutes;
1185
+ var step = projection.meta.defaults.slotStepMinutes;
1186
+ var now = floorToMinute(toDateTime(runtimeOptions.evaluatedAt || projection.meta.durationCandidateAnchorAt));
1187
+ if (!Number.isFinite(now)) throw availabilityError('INVALID_TARGET_FILTER', 'evaluatedAt 必须是有效时间');
1188
+ var nowAt = formatDateTime(now, projection.meta.timezone, fixedOffsetMinutes);
1189
+ var currentBusinessDate = getDurationBusinessDate(projection, nowAt);
1190
+ var inRequestedDays = function inRequestedDays(date) {
1191
+ return date >= dateRange.startDate && date <= dateRange.endDate;
1192
+ };
1193
+ var periods = (projection.meta.defaults.operatingHours.businessPeriods || []).filter(function (period) {
1194
+ return inRequestedDays(period.businessDate);
1195
+ });
1196
+ // A prepared month includes tomorrow's windows too; the single-day UI must
1197
+ // receive the selected business cycle's end, not tomorrow's closing time.
1198
+ var operatingEndAt = dateRange.startDate === dateRange.endDate && periods.length ? periods.reduce(function (latest, period) {
1199
+ return period.endAt > latest ? period.endAt : latest;
1200
+ }, periods[0].endAt) : undefined;
1201
+ var ranges = [];
1202
+ var duration = resolveRequestedDurationMinutes(product, request);
1203
+ var addRange = function addRange(start, end, businessDate) {
1204
+ if (end <= start) return;
1205
+ var candidate = createDurationTimeRangeWithEnd(product, start, end, projection, fixedOffsetMinutes);
1206
+ candidate.businessDate = businessDate || getDurationBusinessDate(projection, candidate.startAt);
1207
+ if (inRequestedDays(candidate.businessDate)) ranges.push(candidate);
1208
+ };
1209
+ // A flexible end comes from resources that actually cover this exact start,
1210
+ // never from the next future window. Keep alternative real ends separate.
1211
+ var flexibleEnds = function flexibleEnds(start) {
1212
+ var _projection$meta$defa;
1213
+ var operating = operatingRanges.find(function (range) {
1214
+ return range.start <= start && start < range.end;
1215
+ });
1216
+ if (!operating) return [];
1217
+ var businessDate = getDurationBusinessDate(projection, formatDateTime(start, projection.meta.timezone, fixedOffsetMinutes));
1218
+ var period = (_projection$meta$defa = projection.meta.defaults.operatingHours.businessPeriods) === null || _projection$meta$defa === void 0 ? void 0 : _projection$meta$defa.find(function (item) {
1219
+ return item.businessDate === businessDate;
1220
+ });
1221
+ var operatingEnd = Math.min(operating.end, period ? toDateTime(period.endAt) : operating.end);
1222
+ var requiredGroups = (product.requirementGroups || []).filter(function (group) {
1223
+ return group.required !== false;
1224
+ });
1225
+ var groups = requiredGroups.map(function (group) {
1226
+ return projection.resources.filter(function (resource) {
1227
+ return matchesRequirementGroup(group, resource, product, request.partySize);
1228
+ }).filter(function (resource) {
1229
+ var _request$resourceIds;
1230
+ return !((_request$resourceIds = request.resourceIds) !== null && _request$resourceIds !== void 0 && _request$resourceIds.length) || request.resourceIds.some(function (id) {
1231
+ return sameId(id, resource.id);
1232
+ });
1233
+ }).flatMap(function (resource) {
1234
+ return (resourceWindowIndex.get(String(resource.id)) || []).filter(function (range) {
1235
+ return range.start <= start && start < range.end;
1236
+ }).map(function (range) {
1237
+ return Math.min(range.end, operatingEnd);
1238
+ });
1239
+ });
1240
+ });
1241
+ if (groups.some(function (ends) {
1242
+ return ends.length === 0;
1243
+ })) return [];
1244
+ if (!groups.length) return [operatingEnd];
1245
+ return Array.from(new Set(groups.flat())).filter(function (end) {
1246
+ return groups.every(function (ends) {
1247
+ return ends.some(function (availableEnd) {
1248
+ return availableEnd >= end;
1249
+ });
1250
+ });
1251
+ }).sort(function (left, right) {
1252
+ return left - right;
1253
+ });
1254
+ };
1255
+ if (product.isFlexibleDuration) {
1256
+ // Preserve the existing continuous-window UI, with the business-day label.
1257
+ periods.forEach(function (period) {
1258
+ var periodRange = normalizeAbsoluteRange(period);
1259
+ baseRanges.forEach(function (range) {
1260
+ var start = Math.max(range.start, periodRange.start, now);
1261
+ var end = Math.min(range.end, periodRange.end);
1262
+ if (start < end) addRange(start, end, period.businessDate);
1263
+ });
1264
+ });
1265
+ } else {
1266
+ periods.forEach(function (period) {
1267
+ var periodRange = normalizeAbsoluteRange(period);
1268
+ var anchor = 60 % step === 0 ? toDateStart(period.businessDate) : periodRange.start;
1269
+ baseRanges.forEach(function (range) {
1270
+ var lower = Math.max(range.start, periodRange.start, now);
1271
+ var upper = Math.min(range.end, periodRange.end);
1272
+ var cursor = anchor + Math.ceil((lower - anchor) / (step * 60000)) * step * 60000;
1273
+ for (; cursor + duration * 60000 <= upper; cursor += step * 60000) {
1274
+ addRange(cursor, cursor + duration * 60000, period.businessDate);
1275
+ }
1276
+ });
1277
+ });
1278
+ }
1279
+ var unavailableCurrentTime;
1280
+ if (inRequestedDays(currentBusinessDate)) {
1281
+ if (product.isFlexibleDuration) {
1282
+ var ends = flexibleEnds(now);
1283
+ ends.forEach(function (end) {
1284
+ return addRange(now, end, currentBusinessDate);
1285
+ });
1286
+ if (!ends.length) {
1287
+ unavailableCurrentTime = {
1288
+ productId: product.id,
1289
+ startAt: nowAt,
1290
+ date: formatDate(now),
1291
+ businessDate: currentBusinessDate,
1292
+ startTime: formatTime(now),
1293
+ status: 'unavailable',
1294
+ reasonCodes: [operatingRanges.some(function (range) {
1295
+ return range.start <= now && now < range.end;
1296
+ }) ? 'outside_resource_window' : 'outside_operating_hours']
1297
+ };
1298
+ }
1299
+ } else {
1300
+ // Even outside a working window the fixed product has a real end. Query
1301
+ // reports unavailable; POS manual capabilities remain a separate policy.
1302
+ addRange(now, now + duration * 60000, currentBusinessDate);
1303
+ }
1304
+ }
1305
+ var rememberedAt = (_request$rememberedSt = request.rememberedStartAtByProductId) === null || _request$rememberedSt === void 0 ? void 0 : _request$rememberedSt[String(product.id)];
1306
+ if (rememberedAt !== undefined) {
1307
+ var start = toDateTime(rememberedAt);
1308
+ if (!Number.isFinite(start)) throw availabilityError('INVALID_TARGET_FILTER', '记忆开始时间必须是完整日期时间');
1309
+ if (product.isFlexibleDuration) {
1310
+ flexibleEnds(start).forEach(function (end) {
1311
+ return addRange(start, end);
1312
+ });
1313
+ } else {
1314
+ addRange(start, start + duration * 60000);
1315
+ }
1316
+ }
1317
+ var editingAt = (_request$editingStart = request.editingStartAtByProductId) === null || _request$editingStart === void 0 ? void 0 : _request$editingStart[String(product.id)];
1318
+ if (editingAt !== undefined) {
1319
+ var _request$durationMinu3;
1320
+ var _start = toDateTime(editingAt);
1321
+ var editingDuration = Number((_request$durationMinu3 = request.durationMinutesByProductId) === null || _request$durationMinu3 === void 0 ? void 0 : _request$durationMinu3[String(product.id)]);
1322
+ if (!Number.isFinite(_start) || !Number.isInteger(editingDuration) || editingDuration <= 0) {
1323
+ throw availabilityError('INVALID_TARGET_FILTER', '编辑时间必须包含完整开始日期时间和明确的正整数时长');
1324
+ }
1325
+ // Editing restores the original interval, including its actual overnight
1326
+ // date. It neither adopts the current grid nor recomputes a flexible end.
1327
+ if (request.allowOutsideOperatingHoursForRequestedStartTimes || operatingRanges.some(function (range) {
1328
+ return range.start <= _start && _start < range.end;
1329
+ })) {
1330
+ addRange(_start, addMinutesZoned(_start, editingDuration, projection.meta.timezone));
1331
+ }
1332
+ }
1333
+
1334
+ // Explicit custom input keeps its existing start + requested duration
1335
+ // semantics. Remembered input above must never use this default-30 path.
1336
+ if (dateRange.startDate === dateRange.endDate) {
1337
+ resolveRequestedDurationStartTimes(product, request).forEach(function (startTime) {
1338
+ var sameDayStart = toDateTimeInDate(dateRange.startDate, startTime);
1339
+ var period = periods.find(function (item) {
1340
+ return item.businessDate === dateRange.startDate;
1341
+ });
1342
+ var periodRange = period ? normalizeAbsoluteRange(period) : null;
1343
+ var nextDayStart = addLocalCalendarDays(sameDayStart, 1);
1344
+ // HH:mm is entered within a selected business day, whose early hours
1345
+ // may belong to the next calendar day. Do not move other out-of-hours
1346
+ // manual input to tomorrow merely because the business closes overnight.
1347
+ var start = periodRange && !(periodRange.start <= sameDayStart && sameDayStart < periodRange.end) && periodRange.start <= nextDayStart && nextDayStart < periodRange.end ? nextDayStart : sameDayStart;
1348
+ if (request.allowOutsideOperatingHoursForRequestedStartTimes || operatingRanges.some(function (range) {
1349
+ return range.start <= start && start < range.end;
1350
+ })) {
1351
+ addRange(start, start + duration * 60000);
1352
+ }
1353
+ });
1354
+ }
1355
+ return _objectSpread(_objectSpread({
1356
+ productId: product.id,
1357
+ title: product.title,
1358
+ kind: product.kind,
1359
+ slotStepMinutes: step
1360
+ }, operatingEndAt ? {
1361
+ operatingEndAt: operatingEndAt
1362
+ } : {}), {}, {
1363
+ ranges: dedupeProductRanges(ranges)
1364
+ }, unavailableCurrentTime ? {
1365
+ unavailableCurrentTime: unavailableCurrentTime
1366
+ } : {});
1367
+ }
1111
1368
  export function getProductTimeRanges(projection) {
1112
1369
  var _extractFixedOffsetMi3, _request$productIds;
1113
1370
  var request = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
@@ -1173,6 +1430,19 @@ export function getProductTimeRanges(projection) {
1173
1430
  return current === null ? ranges : intersectRangeLists(current, ranges);
1174
1431
  }, null) || [] : null;
1175
1432
  var baseRanges = resourceRanges === null ? operatingRanges : intersectRangeLists(resourceRanges, operatingRanges);
1433
+ if (runtimeOptions.useDurationTimeGrid) {
1434
+ return getAlignedDurationRanges({
1435
+ projection: projection,
1436
+ product: product,
1437
+ request: request,
1438
+ runtimeOptions: runtimeOptions,
1439
+ dateRange: dateRange,
1440
+ operatingRanges: operatingRanges,
1441
+ baseRanges: baseRanges,
1442
+ resourceWindowIndex: resourceWindowIndex,
1443
+ fixedOffsetMinutes: fixedOffsetMinutes
1444
+ });
1445
+ }
1176
1446
  var durationMinutes = resolveRequestedDurationMinutes(product, request);
1177
1447
  var flexibleStartAt = function () {
1178
1448
  if (!product.isFlexibleDuration) return undefined;
@@ -1454,7 +1724,9 @@ function buildEvaluationContext(params) {
1454
1724
  selectionsByGroupKey: selectionsByGroupKey,
1455
1725
  useExactDurationCandidateMinute: params.useExactDurationCandidateMinute === true,
1456
1726
  durationCandidateAnchorAtMs: Number.isFinite(durationCandidateAnchorAt) ? floorToMinute(durationCandidateAnchorAt) : null,
1457
- allowExcludedScheduleDateOverride: params.allowExcludedScheduleDateOverride === true
1727
+ allowExcludedScheduleDateOverride: params.allowExcludedScheduleDateOverride === true,
1728
+ useDurationTimeGrid: params.useDurationTimeGrid === true,
1729
+ enforceSaleCutoff: params.enforceSaleCutoff === true
1458
1730
  };
1459
1731
  }
1460
1732
  function summarizeStatuses(statuses) {
@@ -1504,7 +1776,7 @@ function summarizeStatusAggregate(aggregate) {
1504
1776
  return 'unavailable';
1505
1777
  }
1506
1778
  function evaluateMatchedResourceSummary(params) {
1507
- var _ref6, _params$matchedCell$m;
1779
+ var _ref8, _params$matchedCell$m;
1508
1780
  var isPast = params.candidateRange.endMs <= params.evaluationContext.evaluatedAtMs;
1509
1781
  if (!params.matchedCell) {
1510
1782
  return {
@@ -1516,7 +1788,7 @@ function evaluateMatchedResourceSummary(params) {
1516
1788
  };
1517
1789
  }
1518
1790
  var remainingCapacity = Math.max(0, params.matchedCell.remainingCapacity || 0);
1519
- var maxCapacity = Math.max(0, (_ref6 = (_params$matchedCell$m = params.matchedCell.maxCapacity) !== null && _params$matchedCell$m !== void 0 ? _params$matchedCell$m : params.resourceCapacity) !== null && _ref6 !== void 0 ? _ref6 : 0);
1791
+ var maxCapacity = Math.max(0, (_ref8 = (_params$matchedCell$m = params.matchedCell.maxCapacity) !== null && _params$matchedCell$m !== void 0 ? _params$matchedCell$m : params.resourceCapacity) !== null && _ref8 !== void 0 ? _ref8 : 0);
1520
1792
  var maxPartySize = isPast ? 0 : remainingCapacity;
1521
1793
  var status = function () {
1522
1794
  if (isPast) return 'past';
@@ -1942,6 +2214,8 @@ export function queryAvailabilityProjection(projection, request) {
1942
2214
  projection: projection,
1943
2215
  evaluatedAt: evaluatedAt,
1944
2216
  resourceIds: request.resourceIds,
2217
+ useDurationTimeGrid: runtimeOptions.useDurationTimeGrid,
2218
+ enforceSaleCutoff: runtimeOptions.enforceSaleCutoff,
1945
2219
  useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
1946
2220
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
1947
2221
  });
@@ -2032,6 +2306,8 @@ export function queryAvailabilityProjection(projection, request) {
2032
2306
  partySize: normalizedPartySize
2033
2307
  }, {
2034
2308
  evaluatedAt: evaluatedAt,
2309
+ useDurationTimeGrid: runtimeOptions.useDurationTimeGrid,
2310
+ enforceSaleCutoff: runtimeOptions.enforceSaleCutoff,
2035
2311
  useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
2036
2312
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
2037
2313
  });
@@ -2060,7 +2336,8 @@ export function queryAvailabilityProjection(projection, request) {
2060
2336
  candidateRangeCache: candidateRangeCache,
2061
2337
  evaluationContext: evaluationContext
2062
2338
  });
2063
- var aggregate = byDate.get(candidate.date) || {
2339
+ var candidateDate = runtimeOptions.useDurationTimeGrid ? candidate.businessDate || candidate.date : candidate.date;
2340
+ var aggregate = byDate.get(candidateDate) || {
2064
2341
  availableCount: 0,
2065
2342
  totalCount: 0,
2066
2343
  maxPartySize: 0,
@@ -2080,8 +2357,26 @@ export function queryAvailabilityProjection(projection, request) {
2080
2357
  evaluated.reasonCodes.forEach(function (reasonCode) {
2081
2358
  return aggregate.reasonCodeSet.add(reasonCode);
2082
2359
  });
2083
- byDate.set(candidate.date, aggregate);
2360
+ byDate.set(candidateDate, aggregate);
2084
2361
  });
2362
+ if (group.unavailableCurrentTime) {
2363
+ var current = group.unavailableCurrentTime;
2364
+ var aggregate = byDate.get(current.businessDate) || {
2365
+ availableCount: 0,
2366
+ totalCount: 0,
2367
+ maxPartySize: 0,
2368
+ remainingCapacity: 0,
2369
+ maxCapacity: 0,
2370
+ reasonCodeSet: new Set(),
2371
+ statusAggregate: createStatusAggregate()
2372
+ };
2373
+ aggregate.totalCount += 1;
2374
+ pushStatusAggregate(aggregate.statusAggregate, 'unavailable');
2375
+ current.reasonCodes.forEach(function (reason) {
2376
+ return aggregate.reasonCodeSet.add(reason);
2377
+ });
2378
+ byDate.set(current.businessDate, aggregate);
2379
+ }
2085
2380
  var dates = enumerateDates(dateRange.startDate, dateRange.endDate).map(function (date) {
2086
2381
  var aggregate = byDate.get(date);
2087
2382
  return {
@@ -2143,10 +2438,22 @@ export function queryAvailabilityProjection(projection, request) {
2143
2438
  evaluated.reasonCodes.forEach(function (reasonCode) {
2144
2439
  return productReasonCodeSet.add(reasonCode);
2145
2440
  });
2146
- var dateAggregate = dateStatusMap.get(candidate.date) || createStatusAggregate();
2441
+ var candidateDate = runtimeOptions.useDurationTimeGrid ? candidate.businessDate || candidate.date : candidate.date;
2442
+ var dateAggregate = dateStatusMap.get(candidateDate) || createStatusAggregate();
2147
2443
  pushStatusAggregate(dateAggregate, evaluated.status);
2148
- dateStatusMap.set(candidate.date, dateAggregate);
2444
+ dateStatusMap.set(candidateDate, dateAggregate);
2149
2445
  });
2446
+ if (group.unavailableCurrentTime) {
2447
+ var current = group.unavailableCurrentTime;
2448
+ totalTimeCount += 1;
2449
+ pushStatusAggregate(productStatusAggregate, 'unavailable');
2450
+ current.reasonCodes.forEach(function (reason) {
2451
+ return productReasonCodeSet.add(reason);
2452
+ });
2453
+ var dateAggregate = dateStatusMap.get(current.businessDate) || createStatusAggregate();
2454
+ pushStatusAggregate(dateAggregate, 'unavailable');
2455
+ dateStatusMap.set(current.businessDate, dateAggregate);
2456
+ }
2150
2457
  var availableDateCount = Array.from(dateStatusMap.values()).filter(function (aggregate) {
2151
2458
  var status = summarizeStatusAggregate(aggregate);
2152
2459
  return status === 'available' || status === 'limited';
@@ -2233,6 +2540,8 @@ export function validateAvailabilitySelection(projection, params) {
2233
2540
  projection: projection,
2234
2541
  evaluatedAt: evaluatedAt,
2235
2542
  requirementSelections: params.requirementSelections,
2543
+ useDurationTimeGrid: runtimeOptions.useDurationTimeGrid,
2544
+ enforceSaleCutoff: runtimeOptions.enforceSaleCutoff,
2236
2545
  useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
2237
2546
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
2238
2547
  })
@@ -92,6 +92,9 @@ export interface AvailabilityProduct {
92
92
  raw?: Record<string, any>;
93
93
  }
94
94
  export interface AvailabilityResourceWindow extends AvailabilityAbsoluteRange {
95
+ /** Original business day and opening anchor, before coverage clipping. */
96
+ businessDate?: string;
97
+ openingAnchorAt?: string;
95
98
  source?: string;
96
99
  raw?: Record<string, any>;
97
100
  }
@@ -101,10 +104,15 @@ export interface AvailabilityOperatingHoursSnapshot {
101
104
  scheduleIds: AvailabilityId[];
102
105
  missingScheduleIds: AvailabilityId[];
103
106
  windows: AvailabilityResourceWindow[];
107
+ /** Complete business cycles; lunch gaps remain in windows, not in this envelope. */
108
+ businessPeriods?: AvailabilityBusinessPeriod[];
104
109
  /** Schedule windows omitted only because their date is excluded. POS may use
105
110
  * these to surface an unavailable, manually selectable candidate. */
106
111
  excludedWindows?: AvailabilityResourceWindow[];
107
112
  }
113
+ export interface AvailabilityBusinessPeriod extends AvailabilityAbsoluteRange {
114
+ businessDate: string;
115
+ }
108
116
  export interface AvailabilityResource {
109
117
  id: AvailabilityId;
110
118
  formId?: AvailabilityId;
@@ -212,6 +220,17 @@ export interface ProductTimeRange extends AvailabilityDisplayRange {
212
220
  bookingEndAt: string;
213
221
  scheduleRefs: AvailabilityScheduleRef[];
214
222
  primaryScheduleRef?: AvailabilityScheduleRef;
223
+ /** Business-day label. date/startAt keep the actual calendar date. */
224
+ businessDate?: string;
225
+ }
226
+ export interface UnavailableCurrentTime {
227
+ productId: AvailabilityId;
228
+ startAt: string;
229
+ date: string;
230
+ businessDate: string;
231
+ startTime: string;
232
+ status: 'unavailable';
233
+ reasonCodes: string[];
215
234
  }
216
235
  export interface ProductTimeRangeGroup {
217
236
  productId: AvailabilityId;
@@ -221,6 +240,8 @@ export interface ProductTimeRangeGroup {
221
240
  /** 单日查询对应营业窗口的最终结束时刻,不受资源排班是否为空影响。 */
222
241
  operatingEndAt?: string;
223
242
  ranges: ProductTimeRange[];
243
+ /** A display-only current item when flexible duration has no valid end. Never submit it. */
244
+ unavailableCurrentTime?: UnavailableCurrentTime;
224
245
  }
225
246
  export interface AvailabilityAssignment extends AvailabilityAbsoluteRange {
226
247
  productId: AvailabilityId;
@@ -242,6 +263,10 @@ export interface GetProductTimeRangesRequest {
242
263
  partySize?: number;
243
264
  durationMinutesByProductId?: Record<string, number>;
244
265
  durationStartTimesByProductId?: Record<string, string[]>;
266
+ /** Restore only the exact remembered start; recompute the end from current product/windows. */
267
+ rememberedStartAtByProductId?: Record<string, string>;
268
+ /** Edit only: preserve the full actual start plus an explicit durationMinutesByProductId. */
269
+ editingStartAtByProductId?: Record<string, string>;
245
270
  /**
246
271
  * POS 手工输入时间的兼容开关:只为明确请求的 start time 补候选,
247
272
  * 不改变常规候选列表仍按营业时间生成的规则。
@@ -250,6 +275,10 @@ export interface GetProductTimeRangesRequest {
250
275
  }
251
276
  export interface GetProductTimeRangesRuntimeOptions {
252
277
  evaluatedAt?: string;
278
+ /** Enabled by the POS/Kiosk facade only; other consumers retain their existing grid. */
279
+ useDurationTimeGrid?: boolean;
280
+ /** Automatic remembered selection must not use POS opening-minute cutoff exceptions. */
281
+ enforceSaleCutoff?: boolean;
253
282
  /**
254
283
  * Internal POS capability: fixed-duration candidates start from the stable
255
284
  * context anchor's current minute instead of rounding up to ten minutes, and
@@ -10,6 +10,10 @@ export declare class ScheduleModule extends BaseModule implements Module, Schedu
10
10
  private openCache;
11
11
  private fatherModule;
12
12
  private hasLoadedScheduleList;
13
+ private scheduleListPromise;
14
+ private scheduleListRequestVersion;
15
+ private scheduleCatalogScope;
16
+ private otherParams;
13
17
  constructor(name?: string, version?: string);
14
18
  initialize(core: PisellCore, options: ModuleOptions): Promise<void>;
15
19
  /**
@@ -19,6 +23,9 @@ export declare class ScheduleModule extends BaseModule implements Module, Schedu
19
23
  * scheduleModule.updateOtherParams({ openCache: true, cacheId: 'cache-2' });
20
24
  */
21
25
  updateOtherParams(params: Record<string, any>): void;
26
+ private syncScheduleCatalogScope;
27
+ private resetScheduleCatalog;
28
+ destroy(): void;
22
29
  /**
23
30
  * 加载当前店铺下所有 schedule
24
31
  *
@@ -27,6 +34,7 @@ export declare class ScheduleModule extends BaseModule implements Module, Schedu
27
34
  loadAllSchedule(options?: {
28
35
  useCache?: boolean;
29
36
  }): Promise<void>;
37
+ private loadScheduleCatalog;
30
38
  setScheduleList(list: ScheduleItem[]): void;
31
39
  private syncScheduleMap;
32
40
  getScheduleList(): ScheduleItem[];