@pisell/pisellos 2.2.299 → 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.
@@ -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 {
@@ -252,6 +257,11 @@ export interface GetProductTimeRangesRuntimeOptions {
252
257
  * disabled.
253
258
  */
254
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;
255
265
  }
256
266
  export interface QueryAvailabilityBaseRequest {
257
267
  productIds?: AvailabilityId[];
@@ -638,6 +638,22 @@ function normalizeResource(raw, fixedOffsetMinutes = (0, _localClock.captureRunt
638
638
  const id = raw.resourceId ?? raw.resource_id ?? raw.id;
639
639
  if (id === undefined || id === null || id === '') return null;
640
640
  const rawWindows = raw.windows || raw.times || [];
641
+ const rawExcludedWindows = raw.excludedWindows || raw.excluded_windows || [];
642
+ const normalizeWindows = windows => (Array.isArray(windows) ? windows : []).flatMap(window => {
643
+ const range = normalizeAvailabilityLocalDateTimeRange({
644
+ startAt: window.startAt || window.start_at || window.start,
645
+ endAt: window.endAt || window.end_at || window.end,
646
+ fixedOffsetMinutes,
647
+ rollOverEnd: true
648
+ });
649
+ if (!range) return [];
650
+ return [{
651
+ startAt: range.startAt,
652
+ endAt: range.endAt,
653
+ source: window.source,
654
+ raw: window
655
+ }];
656
+ });
641
657
  return {
642
658
  id,
643
659
  formId: raw.formId ?? raw.form_id ?? raw.resource_form_id,
@@ -645,21 +661,8 @@ function normalizeResource(raw, fixedOffsetMinutes = (0, _localClock.captureRunt
645
661
  code: raw.code,
646
662
  resourceType: normalizeResourceType(raw.type || raw.resourceType),
647
663
  capacity: Math.max(1, Number(raw.capacity || raw.max_capacity || 1) || 1),
648
- windows: (Array.isArray(rawWindows) ? rawWindows : []).flatMap(window => {
649
- const range = normalizeAvailabilityLocalDateTimeRange({
650
- startAt: window.startAt || window.start_at || window.start,
651
- endAt: window.endAt || window.end_at || window.end,
652
- fixedOffsetMinutes,
653
- rollOverEnd: true
654
- });
655
- if (!range) return [];
656
- return [{
657
- startAt: range.startAt,
658
- endAt: range.endAt,
659
- source: window.source,
660
- raw: window
661
- }];
662
- }),
664
+ windows: normalizeWindows(rawWindows),
665
+ excludedWindows: normalizeWindows(rawExcludedWindows),
663
666
  raw
664
667
  };
665
668
  }
@@ -678,6 +681,17 @@ function dateRangeDays(dateRange) {
678
681
  }
679
682
  return dates;
680
683
  }
684
+ function getExcludedScheduleDateOverrideTimePoints(date, schedule) {
685
+ if (!schedule.repeat_rule?.excluded_date?.length) return [];
686
+ if ((0, _getDateIsInSchedule.getScheduleStartEndTimePoints)(date, [schedule]).length > 0) return [];
687
+ return (0, _getDateIsInSchedule.getScheduleStartEndTimePoints)(date, [{
688
+ ...schedule,
689
+ repeat_rule: {
690
+ ...schedule.repeat_rule,
691
+ excluded_date: []
692
+ }
693
+ }]);
694
+ }
681
695
  function normalizeResourceOccupancy(rawEvent, resourceId, source = 'remote', fixedOffsetMinutes = (0, _localClock.captureRuntimeOffsetMinutes)()) {
682
696
  const range = normalizeAvailabilityLocalDateTimeRange({
683
697
  startAt: rawEvent.start_at ?? rawEvent.startAt ?? rawEvent.start_time ?? rawEvent.startTime,
@@ -770,7 +784,26 @@ function buildAvailabilityResourcesFromV2(params) {
770
784
  }
771
785
  }];
772
786
  })));
787
+ const excludedWindows = dates.flatMap(date => schedules.flatMap(schedule => getExcludedScheduleDateOverrideTimePoints(date, schedule).flatMap(slot => {
788
+ const range = normalizeAvailabilityLocalDateTimeRange({
789
+ startAt: slot.start_at,
790
+ endAt: slot.end_at,
791
+ fixedOffsetMinutes,
792
+ rollOverEnd: true
793
+ });
794
+ if (!range) return [];
795
+ return [{
796
+ startAt: range.startAt,
797
+ endAt: range.endAt,
798
+ source: `resource_schedule_excluded:${schedule.id}`,
799
+ raw: {
800
+ scheduleId: schedule.id,
801
+ excludedDate: date
802
+ }
803
+ }];
804
+ })));
773
805
  resource.windows = materializedWindows.length > 0 ? materializedWindows : explicitWindows;
806
+ resource.excludedWindows = [...(resource.excludedWindows || []), ...excludedWindows];
774
807
  if (resource.windows.length === 0 && missingScheduleIds.length > 0) {
775
808
  resource.windows = buildResourceWindowFallbackTimes({
776
809
  raw,
@@ -1011,7 +1044,7 @@ function buildBookingFromAvailabilitySelection(params) {
1011
1044
  }
1012
1045
  };
1013
1046
  }
1014
- const POS_OVERRIDABLE_AVAILABILITY_CONFLICT_CODES = new Set(['past', 'booking_cutoff', 'resource_full', 'resource_unavailable', 'resource_capacity_exceeded',
1047
+ const POS_OVERRIDABLE_AVAILABILITY_CONFLICT_CODES = new Set(['past', 'booking_cutoff', 'schedule_excluded_date', 'resource_full', 'resource_unavailable', 'resource_capacity_exceeded',
1015
1048
  // A required group whose selected resource is outside its window is surfaced
1016
1049
  // as missing_resource at group level. Structural validation below still
1017
1050
  // rejects a genuinely missing selection.
@@ -2118,11 +2151,31 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
2118
2151
  source: `operating_schedule:${descriptor.scheduleIds.map(String).join(',')}`
2119
2152
  }] : [];
2120
2153
  }));
2154
+ const excludedWindows = dateRangeDays(params.dateRange).flatMap(date => schedules.flatMap(schedule => getExcludedScheduleDateOverrideTimePoints(date, schedule).flatMap(slot => {
2155
+ const range = normalizeAvailabilityLocalDateTimeRange({
2156
+ startAt: slot.start_at,
2157
+ endAt: slot.end_at,
2158
+ fixedOffsetMinutes: this.getAvailabilityRuntimeOffsetMinutes(),
2159
+ rollOverEnd: true
2160
+ });
2161
+ return range ? [{
2162
+ startAt: range.startAt,
2163
+ endAt: range.endAt,
2164
+ source: `operating_schedule_excluded:${schedule.id}`,
2165
+ raw: {
2166
+ scheduleId: schedule.id,
2167
+ excludedDate: date
2168
+ }
2169
+ }] : [];
2170
+ })));
2121
2171
  return {
2122
2172
  source: descriptor.source,
2123
2173
  scheduleIds: [...descriptor.scheduleIds],
2124
2174
  missingScheduleIds,
2125
- windows
2175
+ windows,
2176
+ ...(excludedWindows.length > 0 ? {
2177
+ excludedWindows
2178
+ } : {})
2126
2179
  };
2127
2180
  }
2128
2181
  async loadAvailabilityProducts(params) {
@@ -2820,7 +2873,8 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
2820
2873
  } : {})
2821
2874
  }, {
2822
2875
  evaluatedAt: this.getAvailabilityRuntimeDateTime(),
2823
- allowSessionCustomRanges: isPosAvailabilityRequest
2876
+ allowSessionCustomRanges: isPosAvailabilityRequest,
2877
+ allowExcludedScheduleDateOverride: isPosAvailabilityRequest
2824
2878
  }).map(group => ({
2825
2879
  ...group,
2826
2880
  ranges: group.ranges.map(candidate => this.decorateAvailabilityCandidate(context.contextId, contextVersion, candidate))
@@ -2835,7 +2889,10 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
2835
2889
  refreshed
2836
2890
  } = await this.ensureAvailabilityContextProjection(contextId, 'query_booking_availability');
2837
2891
  this.assertContextualQueryFreshness(context, request);
2838
- const result = (0, _ResourcePlanner.queryAvailabilityProjection)(projectionEntry.projection, request);
2892
+ const isPosAvailabilityRequest = String(this.otherParams?.platform ?? '').trim().toLowerCase() === 'pos';
2893
+ const result = (0, _ResourcePlanner.queryAvailabilityProjection)(projectionEntry.projection, request, {
2894
+ allowExcludedScheduleDateOverride: isPosAvailabilityRequest
2895
+ });
2839
2896
  const contextVersion = context.activeVersion;
2840
2897
  const contextualResult = result.target === 'time' ? {
2841
2898
  ...result,
@@ -3092,7 +3149,8 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
3092
3149
  } : {})
3093
3150
  } : {})
3094
3151
  }, {
3095
- allowSessionCustomRanges: allowPosAvailabilityOverride
3152
+ allowSessionCustomRanges: allowPosAvailabilityOverride,
3153
+ allowExcludedScheduleDateOverride: allowPosAvailabilityOverride
3096
3154
  }).flatMap(group => group.ranges);
3097
3155
  const refreshedCandidateBase = refreshedRanges.find(candidate => candidate.startAt === params.candidate.startAt && candidate.endAt === params.candidate.endAt && candidate.bookingStartAt === params.candidate.bookingStartAt && candidate.bookingEndAt === params.candidate.bookingEndAt);
3098
3156
  if (!refreshedCandidateBase) {
@@ -3113,6 +3171,8 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
3113
3171
  requirementSelections: params.requirementSelections,
3114
3172
  partySize,
3115
3173
  bookingCount
3174
+ }, {
3175
+ allowExcludedScheduleDateOverride: allowPosAvailabilityOverride
3116
3176
  });
3117
3177
  if (allowPosAvailabilityOverride && !validation.ok && validation.conflicts.every(conflict => POS_OVERRIDABLE_AVAILABILITY_CONFLICT_CODES.has(conflict.code))) {
3118
3178
  const forced = buildPosForcedAvailabilityAssignments({
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "2.2.299",
4
+ "version": "2.2.300",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",