@pisell/pisellos 2.2.298 → 2.2.300

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.
@@ -1,5 +1,5 @@
1
1
  import type { AvailabilityProjection, AvailabilityProjectionInput, AvailabilityQuery, AvailabilityQueryResult, AvailabilitySelectionValidationParams, AvailabilitySelectionValidationResult, GetProductTimeRangesRequest, GetProductTimeRangesRuntimeOptions, ProductTimeRangeGroup } from './types';
2
2
  export declare function createAvailabilityProjection(input: AvailabilityProjectionInput): AvailabilityProjection;
3
3
  export declare function getProductTimeRanges(projection: AvailabilityProjection, request?: GetProductTimeRangesRequest, runtimeOptions?: GetProductTimeRangesRuntimeOptions): ProductTimeRangeGroup[];
4
- export declare function queryAvailabilityProjection(projection: AvailabilityProjection, request: AvailabilityQuery): AvailabilityQueryResult;
5
- export declare function validateAvailabilitySelection(projection: AvailabilityProjection, params: AvailabilitySelectionValidationParams): AvailabilitySelectionValidationResult;
4
+ export declare function queryAvailabilityProjection(projection: AvailabilityProjection, request: AvailabilityQuery, runtimeOptions?: GetProductTimeRangesRuntimeOptions): AvailabilityQueryResult;
5
+ export declare function validateAvailabilitySelection(projection: AvailabilityProjection, params: AvailabilitySelectionValidationParams, runtimeOptions?: GetProductTimeRangesRuntimeOptions): AvailabilitySelectionValidationResult;
@@ -175,8 +175,70 @@ function addLeadWindow(base, unit, unitType, _timezoneName) {
175
175
  if (unitType === 'hours') return addLocalHours(base, unit);
176
176
  return addLocalMinutes(base, unit);
177
177
  }
178
+ function normalizedWindowContainsRange(windows, candidateRange, timezoneName) {
179
+ return windows.some(function (window) {
180
+ var normalized = normalizeAbsoluteRange(window, timezoneName);
181
+ return Boolean(normalized && contains(normalized, candidateRange));
182
+ });
183
+ }
184
+ function normalizedWindowsContainDate(windows, date, timezoneName) {
185
+ return windows.some(function (window) {
186
+ var normalized = normalizeAbsoluteRange(window, timezoneName);
187
+ return Boolean(normalized && formatDate(normalized.start, timezoneName) === date);
188
+ });
189
+ }
190
+ function isRangeFromExcludedWindows(params) {
191
+ var candidateDate = formatDate(params.candidateRange.start, params.timezoneName);
192
+ var hasNormalWindowOnDate = normalizedWindowsContainDate(params.normalWindows, candidateDate, params.timezoneName);
193
+ var hasExcludedWindowOnDate = normalizedWindowsContainDate(params.excludedWindows, candidateDate, params.timezoneName);
194
+ if (!hasNormalWindowOnDate && hasExcludedWindowOnDate) return true;
195
+ return !normalizedWindowContainsRange(params.normalWindows, params.candidateRange, params.timezoneName) && normalizedWindowContainsRange(params.excludedWindows, params.candidateRange, params.timezoneName);
196
+ }
197
+ function isCandidateFromExcludedScheduleDate(params) {
198
+ var projection = params.projection,
199
+ product = params.product,
200
+ candidate = params.candidate,
201
+ candidateRange = params.candidateRange;
202
+ var operatingHours = projection.meta.defaults.operatingHours;
203
+ if (isRangeFromExcludedWindows({
204
+ normalWindows: operatingHours.windows,
205
+ excludedWindows: operatingHours.excludedWindows || [],
206
+ candidateRange: candidateRange,
207
+ timezoneName: projection.meta.timezone
208
+ })) {
209
+ return true;
210
+ }
211
+ if (product.kind !== 'session' && product.kind !== 'venue_slot') {
212
+ return false;
213
+ }
214
+ if (candidate.source !== 'session_schedule') {
215
+ var hasNormalRule = (product.sessionRules || []).some(function (rule) {
216
+ return matchesScheduleRuleDate(rule, candidate.date, projection.meta.timezone);
217
+ });
218
+ var hasExcludedOverrideRule = (product.sessionRules || []).some(function (rule) {
219
+ return !matchesScheduleRuleDate(rule, candidate.date, projection.meta.timezone) && matchesScheduleRuleDate(rule, candidate.date, projection.meta.timezone, true);
220
+ });
221
+ return !hasNormalRule && hasExcludedOverrideRule;
222
+ }
223
+ var candidateDateRange = {
224
+ startDate: candidate.date,
225
+ endDate: candidate.date
226
+ };
227
+ var candidateIdentity = getProductTimeRangeIdentity(candidate);
228
+ var normalRanges = getSessionRangesForProduct(projection, product, candidateDateRange);
229
+ if (normalRanges.some(function (range) {
230
+ return getProductTimeRangeIdentity(range) === candidateIdentity;
231
+ })) {
232
+ return false;
233
+ }
234
+ return getSessionRangesForProduct(projection, product, candidateDateRange, true).some(function (range) {
235
+ return getProductTimeRangeIdentity(range) === candidateIdentity;
236
+ });
237
+ }
178
238
  function evaluateCandidateTimeGate(params) {
179
- var product = params.product,
239
+ var projection = params.projection,
240
+ product = params.product,
241
+ candidate = params.candidate,
180
242
  candidateRange = params.candidateRange,
181
243
  evaluationContext = params.evaluationContext,
182
244
  timezoneName = params.timezoneName;
@@ -188,6 +250,18 @@ function evaluateCandidateTimeGate(params) {
188
250
  conflictCode: 'past'
189
251
  };
190
252
  }
253
+ if (evaluationContext.allowExcludedScheduleDateOverride && isCandidateFromExcludedScheduleDate({
254
+ projection: projection,
255
+ product: product,
256
+ candidate: candidate,
257
+ candidateRange: candidateRange
258
+ })) {
259
+ return {
260
+ status: 'unavailable',
261
+ reasonCodes: ['schedule_excluded_date'],
262
+ conflictCode: 'schedule_excluded_date'
263
+ };
264
+ }
191
265
  var policy = product.cutOffPolicy;
192
266
  if (!policy) return null;
193
267
  if (resolveCutOffPolicyIssue(policy)) {
@@ -334,7 +408,8 @@ function normalizeCoverage(input) {
334
408
  };
335
409
  }
336
410
  function normalizeResourceWindow(resource, coverage, timezoneName) {
337
- return mergeRanges((resource.windows || []).map(function (window) {
411
+ var includeExcludedWindows = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
412
+ return mergeRanges([].concat(_toConsumableArray(resource.windows || []), _toConsumableArray(includeExcludedWindows ? resource.excludedWindows || [] : [])).map(function (window) {
338
413
  return normalizeAbsoluteRange(window, timezoneName);
339
414
  }).filter(function (window) {
340
415
  return Boolean(window);
@@ -407,12 +482,15 @@ function normalizeResources(resources) {
407
482
  capacity: Math.max(1, Number(resource.capacity || 1) || 1),
408
483
  windows: (resource.windows || []).map(function (window) {
409
484
  return _objectSpread({}, window);
485
+ }),
486
+ excludedWindows: (resource.excludedWindows || []).map(function (window) {
487
+ return _objectSpread({}, window);
410
488
  })
411
489
  });
412
490
  });
413
491
  }
414
492
  function normalizeOperatingHours(params) {
415
- var _params$input, _params$input2, _params$input3;
493
+ var _params$input, _params$input2, _params$input3, _params$input4;
416
494
  var fallbackWindows = enumerateDates(params.dateRange.startDate, params.dateRange.endDate).map(function (date) {
417
495
  var start = toDateTimeInDate(date, params.businessHours.startTime, params.timezoneName);
418
496
  var end = toDateTimeInDate(date, params.businessHours.endTime, params.timezoneName);
@@ -430,26 +508,32 @@ function normalizeOperatingHours(params) {
430
508
  endAt: formatDateTime(range.end, params.timezoneName, params.fixedOffsetMinutes)
431
509
  };
432
510
  });
433
- var windows = mergeRanges(sourceWindows.map(function (window) {
434
- return normalizeAbsoluteRange(window, params.timezoneName);
435
- }).filter(function (window) {
436
- return Boolean(window);
437
- }).map(function (window) {
438
- return clipRange(window, params.coverage);
439
- }).filter(function (window) {
440
- return Boolean(window);
441
- })).map(function (range) {
442
- return {
443
- startAt: formatDateTime(range.start, params.timezoneName, params.fixedOffsetMinutes),
444
- endAt: formatDateTime(range.end, params.timezoneName, params.fixedOffsetMinutes)
445
- };
446
- });
447
- return {
448
- source: ((_params$input = params.input) === null || _params$input === void 0 ? void 0 : _params$input.source) || params.fallbackSource,
449
- scheduleIds: uniqById(((_params$input2 = params.input) === null || _params$input2 === void 0 ? void 0 : _params$input2.scheduleIds) || []),
450
- missingScheduleIds: uniqById(((_params$input3 = params.input) === null || _params$input3 === void 0 ? void 0 : _params$input3.missingScheduleIds) || []),
451
- windows: windows
511
+ var normalizeWindows = function normalizeWindows(source) {
512
+ return mergeRanges(source.map(function (window) {
513
+ return normalizeAbsoluteRange(window, params.timezoneName);
514
+ }).filter(function (window) {
515
+ return Boolean(window);
516
+ }).map(function (window) {
517
+ return clipRange(window, params.coverage);
518
+ }).filter(function (window) {
519
+ return Boolean(window);
520
+ })).map(function (range) {
521
+ return {
522
+ startAt: formatDateTime(range.start, params.timezoneName, params.fixedOffsetMinutes),
523
+ endAt: formatDateTime(range.end, params.timezoneName, params.fixedOffsetMinutes)
524
+ };
525
+ });
452
526
  };
527
+ var windows = normalizeWindows(sourceWindows);
528
+ var excludedWindows = normalizeWindows(((_params$input = params.input) === null || _params$input === void 0 ? void 0 : _params$input.excludedWindows) || []);
529
+ return _objectSpread({
530
+ source: ((_params$input2 = params.input) === null || _params$input2 === void 0 ? void 0 : _params$input2.source) || params.fallbackSource,
531
+ scheduleIds: uniqById(((_params$input3 = params.input) === null || _params$input3 === void 0 ? void 0 : _params$input3.scheduleIds) || []),
532
+ missingScheduleIds: uniqById(((_params$input4 = params.input) === null || _params$input4 === void 0 ? void 0 : _params$input4.missingScheduleIds) || []),
533
+ windows: windows
534
+ }, excludedWindows.length > 0 ? {
535
+ excludedWindows: excludedWindows
536
+ } : {});
453
537
  }
454
538
  function matchesRequirementGroup(requirementGroup, resource, product) {
455
539
  var _requirementGroup$res;
@@ -759,11 +843,12 @@ function resolveProjectionDateRange(projection, requestDateRange) {
759
843
  };
760
844
  }
761
845
  function buildOperatingRanges(projection, dateRange) {
846
+ var includeExcludedWindows = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
762
847
  var coverage = {
763
848
  start: toDateStart(dateRange.startDate, projection.meta.timezone),
764
849
  end: toDateEnd(nextDate(dateRange.endDate), projection.meta.timezone)
765
850
  };
766
- return mergeRanges(projection.meta.defaults.operatingHours.windows.map(function (window) {
851
+ return mergeRanges([].concat(_toConsumableArray(projection.meta.defaults.operatingHours.windows), _toConsumableArray(includeExcludedWindows ? projection.meta.defaults.operatingHours.excludedWindows || [] : [])).map(function (window) {
767
852
  return normalizeAbsoluteRange(window, projection.meta.timezone);
768
853
  }).filter(function (window) {
769
854
  return Boolean(window);
@@ -774,12 +859,13 @@ function buildOperatingRanges(projection, dateRange) {
774
859
  }));
775
860
  }
776
861
  function buildResourceWindowIndex(projection) {
862
+ var includeExcludedWindows = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
777
863
  var coverage = {
778
864
  start: toDateTime(projection.meta.coverage.startAt, projection.meta.timezone),
779
865
  end: toDateTime(projection.meta.coverage.endAt, projection.meta.timezone)
780
866
  };
781
867
  return new Map(projection.resources.map(function (resource) {
782
- return [String(resource.id), normalizeResourceWindow(resource, coverage, projection.meta.timezone)];
868
+ return [String(resource.id), normalizeResourceWindow(resource, coverage, projection.meta.timezone, includeExcludedWindows)];
783
869
  }));
784
870
  }
785
871
  function buildGroupWorkingRanges(params) {
@@ -801,7 +887,7 @@ function buildGroupWorkingRanges(params) {
801
887
  return !filteredResourceIdSet || filteredResourceIdSet.has(String(resource.id));
802
888
  }).map(function (resource) {
803
889
  var _params$resourceWindo;
804
- var windows = ((_params$resourceWindo = params.resourceWindowIndex) === null || _params$resourceWindo === void 0 ? void 0 : _params$resourceWindo.get(String(resource.id))) || normalizeResourceWindow(resource, coverage, projection.meta.timezone);
890
+ var windows = ((_params$resourceWindo = params.resourceWindowIndex) === null || _params$resourceWindo === void 0 ? void 0 : _params$resourceWindo.get(String(resource.id))) || normalizeResourceWindow(resource, coverage, projection.meta.timezone, params.includeExcludedWindows === true);
805
891
  return windows.map(function (window) {
806
892
  return clipRange(window, coverage);
807
893
  }).filter(function (window) {
@@ -848,11 +934,12 @@ function buildGroupWorkingRanges(params) {
848
934
  return mergeRanges(satisfiedRanges);
849
935
  }
850
936
  function materializeScheduleRules(rules, dateRange, timezoneName, fixedOffsetMinutes) {
937
+ var allowExcludedScheduleDates = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
851
938
  var dates = enumerateDates(dateRange.startDate, dateRange.endDate);
852
939
  var seen = new Map();
853
940
  rules.forEach(function (rule) {
854
941
  dates.forEach(function (date) {
855
- if (!matchesScheduleRuleDate(rule, date, timezoneName)) return;
942
+ if (!matchesScheduleRuleDate(rule, date, timezoneName, allowExcludedScheduleDates)) return;
856
943
  var start = toDateTimeInDate(date, rule.startTime, timezoneName);
857
944
  var end = toDateTimeInDate(date, rule.endTime, timezoneName);
858
945
  if (end <= start) end = toDateTimeInDate(nextDate(date, timezoneName), rule.endTime, timezoneName);
@@ -885,8 +972,9 @@ function materializeScheduleRules(rules, dateRange, timezoneName, fixedOffsetMin
885
972
  }
886
973
  function matchesScheduleRuleDate(rule, date, _timezoneName) {
887
974
  var _rule$includeDates, _rule$excludeDates;
975
+ var allowExcludedScheduleDate = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
888
976
  if ((_rule$includeDates = rule.includeDates) !== null && _rule$includeDates !== void 0 && _rule$includeDates.includes(date)) return true;
889
- if ((_rule$excludeDates = rule.excludeDates) !== null && _rule$excludeDates !== void 0 && _rule$excludeDates.includes(date)) return false;
977
+ if (!allowExcludedScheduleDate && (_rule$excludeDates = rule.excludeDates) !== null && _rule$excludeDates !== void 0 && _rule$excludeDates.includes(date)) return false;
890
978
  if (rule.startDate && date < rule.startDate) return false;
891
979
  if (rule.endDate && date > rule.endDate) return false;
892
980
  if (rule.mode === 'designation') {
@@ -942,6 +1030,7 @@ function buildGroupResourceIndex(params) {
942
1030
  }
943
1031
  function getSessionRangesForProduct(projection, product, dateRange) {
944
1032
  var _extractFixedOffsetMi2;
1033
+ var allowExcludedScheduleDates = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
945
1034
  var fixedOffsetMinutes = (_extractFixedOffsetMi2 = extractFixedOffsetMinutes(projection.meta.now)) !== null && _extractFixedOffsetMi2 !== void 0 ? _extractFixedOffsetMi2 : captureRuntimeOffsetMinutes();
946
1035
  var ranges = (product.sessionRanges || []).map(function (range) {
947
1036
  var _range$scheduleRefs2;
@@ -967,7 +1056,7 @@ function getSessionRangesForProduct(projection, product, dateRange) {
967
1056
  primaryScheduleRef: (_range$scheduleRefs2 = range.scheduleRefs) === null || _range$scheduleRefs2 === void 0 ? void 0 : _range$scheduleRefs2[0]
968
1057
  };
969
1058
  }).filter(Boolean);
970
- var ruleRanges = materializeScheduleRules(product.sessionRules || [], dateRange, projection.meta.timezone, fixedOffsetMinutes);
1059
+ var ruleRanges = materializeScheduleRules(product.sessionRules || [], dateRange, projection.meta.timezone, fixedOffsetMinutes, allowExcludedScheduleDates);
971
1060
  return dedupeProductRanges([].concat(_toConsumableArray(ranges), _toConsumableArray(ruleRanges.map(function (range) {
972
1061
  return _objectSpread(_objectSpread({}, range), {}, {
973
1062
  key: "".concat(String(product.id), ":").concat(range.startAt, ":").concat(range.endAt),
@@ -1022,7 +1111,8 @@ export function getProductTimeRanges(projection) {
1022
1111
  var dateRange = resolveProjectionDateRange(projection, request.dateRange);
1023
1112
  var slotStepMinutes = projection.meta.defaults.slotStepMinutes;
1024
1113
  var fixedOffsetMinutes = (_extractFixedOffsetMi3 = extractFixedOffsetMinutes(projection.meta.now)) !== null && _extractFixedOffsetMi3 !== void 0 ? _extractFixedOffsetMi3 : captureRuntimeOffsetMinutes();
1025
- var resourceWindowIndex = buildResourceWindowIndex(projection);
1114
+ var allowExcludedScheduleDateOverride = runtimeOptions.allowExcludedScheduleDateOverride === true;
1115
+ var resourceWindowIndex = buildResourceWindowIndex(projection, allowExcludedScheduleDateOverride);
1026
1116
  var filteredProductIdSet = (_request$productIds = request.productIds) !== null && _request$productIds !== void 0 && _request$productIds.length ? new Set(request.productIds.map(String)) : null;
1027
1117
  return projection.products.filter(function (product) {
1028
1118
  return !filteredProductIdSet || filteredProductIdSet.has(String(product.id));
@@ -1037,7 +1127,7 @@ export function getProductTimeRanges(projection) {
1037
1127
  };
1038
1128
  }
1039
1129
  if (product.kind === 'session' || product.kind === 'venue_slot') {
1040
- var fixedRanges = getSessionRangesForProduct(projection, product, dateRange);
1130
+ var fixedRanges = getSessionRangesForProduct(projection, product, dateRange, allowExcludedScheduleDateOverride);
1041
1131
  var customRanges = [];
1042
1132
  var customDurationMinutes = resolveRequestedSessionDurationMinutes(product, request, runtimeOptions.allowSessionCustomRanges === true);
1043
1133
  var _requestedStartTimes = resolveRequestedDurationStartTimes(product, request, runtimeOptions.allowSessionCustomRanges === true);
@@ -1059,7 +1149,10 @@ export function getProductTimeRanges(projection) {
1059
1149
  var requiredGroups = (product.requirementGroups || []).filter(function (group) {
1060
1150
  return group.required !== false;
1061
1151
  });
1062
- var operatingRanges = buildOperatingRanges(projection, dateRange);
1152
+ var operatingRanges = buildOperatingRanges(projection, dateRange, allowExcludedScheduleDateOverride);
1153
+ var operatingEndAt = dateRange.startDate === dateRange.endDate && operatingRanges.length > 0 ? formatDateTime(Math.max.apply(Math, _toConsumableArray(operatingRanges.map(function (range) {
1154
+ return range.end;
1155
+ }))), projection.meta.timezone, fixedOffsetMinutes) : undefined;
1063
1156
  var resourceRanges = requiredGroups.length ? requiredGroups.map(function (group) {
1064
1157
  return buildGroupWorkingRanges({
1065
1158
  projection: projection,
@@ -1068,7 +1161,8 @@ export function getProductTimeRanges(projection) {
1068
1161
  dateRange: dateRange,
1069
1162
  resourceIds: request.resourceIds,
1070
1163
  partySize: normalizedPartySize,
1071
- resourceWindowIndex: resourceWindowIndex
1164
+ resourceWindowIndex: resourceWindowIndex,
1165
+ includeExcludedWindows: allowExcludedScheduleDateOverride
1072
1166
  });
1073
1167
  }).reduce(function (current, ranges) {
1074
1168
  return current === null ? ranges : intersectRangeLists(current, ranges);
@@ -1127,13 +1221,16 @@ export function getProductTimeRanges(projection) {
1127
1221
  ranges.push(createDurationTimeRange(product, start, durationMinutes, projection, fixedOffsetMinutes));
1128
1222
  });
1129
1223
  }
1130
- return {
1224
+ return _objectSpread(_objectSpread({
1131
1225
  productId: product.id,
1132
1226
  title: product.title,
1133
1227
  kind: product.kind,
1134
- slotStepMinutes: slotStepMinutes,
1228
+ slotStepMinutes: slotStepMinutes
1229
+ }, operatingEndAt ? {
1230
+ operatingEndAt: operatingEndAt
1231
+ } : {}), {}, {
1135
1232
  ranges: dedupeProductRanges(ranges)
1136
- };
1233
+ });
1137
1234
  });
1138
1235
  }
1139
1236
  function aggregateMatchedCells(productId, requirementGroupId, resourceId, candidateRange, indexedCells) {
@@ -1347,7 +1444,8 @@ function buildEvaluationContext(params) {
1347
1444
  evaluatedAt: evaluatedAt,
1348
1445
  evaluatedAtMs: evaluatedAt,
1349
1446
  resourceIdSet: (_params$resourceIds2 = params.resourceIds) !== null && _params$resourceIds2 !== void 0 && _params$resourceIds2.length ? new Set(params.resourceIds.map(String)) : null,
1350
- selectionsByGroupKey: selectionsByGroupKey
1447
+ selectionsByGroupKey: selectionsByGroupKey,
1448
+ allowExcludedScheduleDateOverride: params.allowExcludedScheduleDateOverride === true
1351
1449
  };
1352
1450
  }
1353
1451
  function summarizeStatuses(statuses) {
@@ -1519,7 +1617,8 @@ function evaluateCandidateSummary(projection, candidate, request) {
1519
1617
  var evaluationContext = request.evaluationContext || buildEvaluationContext({
1520
1618
  projection: projection,
1521
1619
  evaluatedAt: request.evaluatedAt,
1522
- resourceIds: request.resourceIds
1620
+ resourceIds: request.resourceIds,
1621
+ allowExcludedScheduleDateOverride: request.allowExcludedScheduleDateOverride
1523
1622
  });
1524
1623
  var requestedPartySize = normalizePartySize(request.partySize);
1525
1624
  var requiredGroups = (product.requirementGroups || []).filter(function (group) {
@@ -1537,7 +1636,9 @@ function evaluateCandidateSummary(projection, candidate, request) {
1537
1636
  });
1538
1637
  });
1539
1638
  var gate = evaluateCandidateTimeGate({
1639
+ projection: projection,
1540
1640
  product: product,
1641
+ candidate: candidate,
1541
1642
  candidateRange: candidateRange,
1542
1643
  evaluationContext: evaluationContext,
1543
1644
  timezoneName: projection.meta.timezone
@@ -1592,7 +1693,8 @@ function evaluateCandidate(projection, candidate, request) {
1592
1693
  projection: projection,
1593
1694
  evaluatedAt: request.evaluatedAt,
1594
1695
  resourceIds: request.resourceIds,
1595
- requirementSelections: request.requirementSelections
1696
+ requirementSelections: request.requirementSelections,
1697
+ allowExcludedScheduleDateOverride: request.allowExcludedScheduleDateOverride
1596
1698
  });
1597
1699
  var requestedPartySize = normalizePartySize(request.partySize);
1598
1700
  var partySize = requestedPartySize !== null && requestedPartySize !== void 0 ? requestedPartySize : 1;
@@ -1615,6 +1717,12 @@ function evaluateCandidate(projection, candidate, request) {
1615
1717
  var options = matchedResources.map(function (resource) {
1616
1718
  var _request$cellIndex, _resource$raw2;
1617
1719
  var matchedCell = aggregateMatchedCells(product.id, requirementGroup.id, resource.id, candidateRange, ((_request$cellIndex = request.cellIndex) === null || _request$cellIndex === void 0 ? void 0 : _request$cellIndex.get([String(product.id), requirementGroup.id, String(resource.id)].join(':'))) || []);
1720
+ var isExcludedScheduleDate = evaluationContext.allowExcludedScheduleDateOverride && isRangeFromExcludedWindows({
1721
+ normalWindows: resource.windows || [],
1722
+ excludedWindows: resource.excludedWindows || [],
1723
+ candidateRange: candidateRange,
1724
+ timezoneName: projection.meta.timezone
1725
+ });
1618
1726
  if (!matchedCell) {
1619
1727
  var _resource$raw;
1620
1728
  var _isPast = candidateRange.endMs <= evaluationContext.evaluatedAtMs;
@@ -1626,7 +1734,7 @@ function evaluateCandidate(projection, candidate, request) {
1626
1734
  resourceType: resource.resourceType,
1627
1735
  status: _isPast ? 'past' : 'unavailable',
1628
1736
  maxPartySize: 0,
1629
- reasonCodes: _isPast ? ['past'] : ['outside_resource_window']
1737
+ reasonCodes: _isPast ? ['past'] : [].concat(_toConsumableArray(isExcludedScheduleDate ? ['schedule_excluded_date'] : []), ['outside_resource_window'])
1630
1738
  };
1631
1739
  }
1632
1740
  var remainingCapacity = matchedCell.remainingCapacity;
@@ -1634,6 +1742,7 @@ function evaluateCandidate(projection, candidate, request) {
1634
1742
  var isPast = candidateRange.endMs <= evaluationContext.evaluatedAtMs;
1635
1743
  var maxPartySize = isPast ? 0 : Math.max(0, remainingCapacity || 0);
1636
1744
  var requiredCapacity = resolveRequiredCapacity(requirementGroup, product, requestedPartySize);
1745
+ var reasonCodes = Array.from(new Set([].concat(_toConsumableArray(matchedCell.reasonCodes), _toConsumableArray(isExcludedScheduleDate ? ['schedule_excluded_date'] : []))));
1637
1746
  var status = function () {
1638
1747
  if (isPast) return 'past';
1639
1748
  if (matchedCell.status === 'unavailable') return 'unavailable';
@@ -1651,7 +1760,7 @@ function evaluateCandidate(projection, candidate, request) {
1651
1760
  remainingCapacity: remainingCapacity,
1652
1761
  maxCapacity: maxCapacity,
1653
1762
  maxPartySize: maxPartySize,
1654
- reasonCodes: isPast ? Array.from(new Set([].concat(_toConsumableArray(matchedCell.reasonCodes), ['past']))) : matchedCell.reasonCodes,
1763
+ reasonCodes: isPast ? Array.from(new Set([].concat(reasonCodes, ['past']))) : reasonCodes,
1655
1764
  matchedCell: matchedCell
1656
1765
  };
1657
1766
  });
@@ -1709,7 +1818,9 @@ function evaluateCandidate(projection, candidate, request) {
1709
1818
  return group.status;
1710
1819
  });
1711
1820
  var gate = evaluateCandidateTimeGate({
1821
+ projection: projection,
1712
1822
  product: product,
1823
+ candidate: candidate,
1713
1824
  candidateRange: candidateRange,
1714
1825
  evaluationContext: evaluationContext,
1715
1826
  timezoneName: projection.meta.timezone
@@ -1798,6 +1909,7 @@ function assertRangesWithinProjection(projection, ranges) {
1798
1909
  }
1799
1910
  export function queryAvailabilityProjection(projection, request) {
1800
1911
  var _extractFixedOffsetMi6, _request$productIds2;
1912
+ var runtimeOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
1801
1913
  var normalizedPartySize = normalizePartySize(request.partySize);
1802
1914
  var evaluatedAt = formatDateTime(localDateToScalar(new Date()), projection.meta.timezone, (_extractFixedOffsetMi6 = extractFixedOffsetMinutes(projection.meta.now)) !== null && _extractFixedOffsetMi6 !== void 0 ? _extractFixedOffsetMi6 : captureRuntimeOffsetMinutes());
1803
1915
  if (request.target === 'time') {
@@ -1820,7 +1932,8 @@ export function queryAvailabilityProjection(projection, request) {
1820
1932
  var evaluationContext = buildEvaluationContext({
1821
1933
  projection: projection,
1822
1934
  evaluatedAt: evaluatedAt,
1823
- resourceIds: request.resourceIds
1935
+ resourceIds: request.resourceIds,
1936
+ allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
1824
1937
  });
1825
1938
  if (request.target === 'time') {
1826
1939
  var candidates = dedupeProductRanges(request.candidates);
@@ -1908,7 +2021,8 @@ export function queryAvailabilityProjection(projection, request) {
1908
2021
  resourceIds: request.resourceIds,
1909
2022
  partySize: normalizedPartySize
1910
2023
  }, {
1911
- evaluatedAt: evaluatedAt
2024
+ evaluatedAt: evaluatedAt,
2025
+ allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
1912
2026
  });
1913
2027
  var candidateGroupMap = new Map(candidateGroups.map(function (group) {
1914
2028
  return [String(group.productId), group];
@@ -2086,6 +2200,7 @@ function summarizeProductStatus(statuses) {
2086
2200
  }
2087
2201
  export function validateAvailabilitySelection(projection, params) {
2088
2202
  var _extractFixedOffsetMi7;
2203
+ var runtimeOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
2089
2204
  var normalizedPartySize = normalizePartySize(params.partySize);
2090
2205
  var normalizedBookingCount = normalizeBookingCount(params.bookingCount);
2091
2206
  assertRangesWithinProjection(projection, [params.candidate]);
@@ -2106,14 +2221,15 @@ export function validateAvailabilitySelection(projection, params) {
2106
2221
  evaluationContext: buildEvaluationContext({
2107
2222
  projection: projection,
2108
2223
  evaluatedAt: evaluatedAt,
2109
- requirementSelections: params.requirementSelections
2224
+ requirementSelections: params.requirementSelections,
2225
+ allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
2110
2226
  })
2111
2227
  });
2112
2228
  var conflicts = [];
2113
2229
  if (evaluated.gate) {
2114
2230
  conflicts.push({
2115
2231
  code: evaluated.gate.conflictCode,
2116
- message: evaluated.gate.status === 'past' ? '候选时间已过期' : '候选时间不满足预订时间门禁',
2232
+ message: evaluated.gate.conflictCode === 'past' ? '候选时间已过期' : evaluated.gate.conflictCode === 'schedule_excluded_date' ? '候选日期已被日程排除' : '候选时间不满足预订时间门禁',
2117
2233
  reasonCodes: evaluated.gate.reasonCodes,
2118
2234
  productId: params.candidate.productId,
2119
2235
  candidateKey: params.candidate.key
@@ -101,6 +101,9 @@ export interface AvailabilityOperatingHoursSnapshot {
101
101
  scheduleIds: AvailabilityId[];
102
102
  missingScheduleIds: AvailabilityId[];
103
103
  windows: AvailabilityResourceWindow[];
104
+ /** Schedule windows omitted only because their date is excluded. POS may use
105
+ * these to surface an unavailable, manually selectable candidate. */
106
+ excludedWindows?: AvailabilityResourceWindow[];
104
107
  }
105
108
  export interface AvailabilityResource {
106
109
  id: AvailabilityId;
@@ -110,6 +113,8 @@ export interface AvailabilityResource {
110
113
  resourceType: AvailabilityResourceType;
111
114
  capacity: number;
112
115
  windows: AvailabilityResourceWindow[];
116
+ /** Resource work windows omitted only by an excluded schedule date. */
117
+ excludedWindows?: AvailabilityResourceWindow[];
113
118
  raw?: Record<string, any>;
114
119
  }
115
120
  export interface AvailabilityOccupancy extends AvailabilityAbsoluteRange {
@@ -213,6 +218,8 @@ export interface ProductTimeRangeGroup {
213
218
  title?: string;
214
219
  kind: AvailabilityProductKind;
215
220
  slotStepMinutes?: number;
221
+ /** 单日查询对应营业窗口的最终结束时刻,不受资源排班是否为空影响。 */
222
+ operatingEndAt?: string;
216
223
  ranges: ProductTimeRange[];
217
224
  }
218
225
  export interface AvailabilityAssignment extends AvailabilityAbsoluteRange {
@@ -250,6 +257,11 @@ export interface GetProductTimeRangesRuntimeOptions {
250
257
  * disabled.
251
258
  */
252
259
  allowSessionCustomRanges?: boolean;
260
+ /**
261
+ * Internal POS capability: materialize candidates whose schedule date was
262
+ * explicitly excluded, while availability evaluation keeps them unavailable.
263
+ */
264
+ allowExcludedScheduleDateOverride?: boolean;
253
265
  }
254
266
  export interface QueryAvailabilityBaseRequest {
255
267
  productIds?: AvailabilityId[];
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
326
326
  date: string;
327
327
  status: string;
328
328
  week: string;
329
- weekNum: 0 | 2 | 1 | 6 | 4 | 3 | 5;
329
+ weekNum: 0 | 2 | 3 | 1 | 5 | 6 | 4;
330
330
  }[]>;
331
331
  submitTimeSlot(timeSlots: TimeSliceItem): void;
332
332
  private getScheduleDataByIds;