@pisell/pisellos 2.2.300 → 2.2.301

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.
@@ -294,10 +294,12 @@ function evaluateCandidateTimeGate(params) {
294
294
  };
295
295
  }
296
296
  if (policy.type === 'before_start') {
297
- // Flexible-duration candidates start at minute precision. Keep the current
298
- // minute selectable instead of treating the freshly generated candidate as
299
- // already started because the query clock still contains seconds.
300
- var hasNotReachedStart = product.isFlexibleDuration ? floorToMinute(now) <= candidateRange.start : now < candidateRange.start;
297
+ // Flexible-duration candidates and POS fixed-duration anchors start at
298
+ // minute precision. Keep that current minute selectable instead of treating
299
+ // the freshly generated candidate as already started because the query
300
+ // clock still contains seconds.
301
+ var usesMinutePrecision = product.isFlexibleDuration || evaluationContext.useExactDurationCandidateMinute && product.kind === 'duration';
302
+ var hasNotReachedStart = usesMinutePrecision ? floorToMinute(now) <= candidateRange.start : now < candidateRange.start;
301
303
  if (hasNotReachedStart) return null;
302
304
  return {
303
305
  status: 'unavailable',
@@ -1179,7 +1181,8 @@ export function getProductTimeRanges(projection) {
1179
1181
  }
1180
1182
  return floorToMinute(evaluatedAt);
1181
1183
  }();
1182
- var durationAnchor = ceilToTenMinutes(toDateTime(projection.meta.durationCandidateAnchorAt, projection.meta.timezone), projection.meta.timezone);
1184
+ var durationCandidateAnchor = toDateTime(projection.meta.durationCandidateAnchorAt, projection.meta.timezone);
1185
+ var durationAnchor = runtimeOptions.useExactDurationCandidateMinute ? floorToMinute(durationCandidateAnchor) : ceilToTenMinutes(durationCandidateAnchor, projection.meta.timezone);
1183
1186
  var requestedStartTimes = resolveRequestedDurationStartTimes(product, request);
1184
1187
  var ranges = [];
1185
1188
  baseRanges.forEach(function (range) {
@@ -1445,6 +1448,7 @@ function buildEvaluationContext(params) {
1445
1448
  evaluatedAtMs: evaluatedAt,
1446
1449
  resourceIdSet: (_params$resourceIds2 = params.resourceIds) !== null && _params$resourceIds2 !== void 0 && _params$resourceIds2.length ? new Set(params.resourceIds.map(String)) : null,
1447
1450
  selectionsByGroupKey: selectionsByGroupKey,
1451
+ useExactDurationCandidateMinute: params.useExactDurationCandidateMinute === true,
1448
1452
  allowExcludedScheduleDateOverride: params.allowExcludedScheduleDateOverride === true
1449
1453
  };
1450
1454
  }
@@ -1933,6 +1937,7 @@ export function queryAvailabilityProjection(projection, request) {
1933
1937
  projection: projection,
1934
1938
  evaluatedAt: evaluatedAt,
1935
1939
  resourceIds: request.resourceIds,
1940
+ useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
1936
1941
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
1937
1942
  });
1938
1943
  if (request.target === 'time') {
@@ -2022,6 +2027,7 @@ export function queryAvailabilityProjection(projection, request) {
2022
2027
  partySize: normalizedPartySize
2023
2028
  }, {
2024
2029
  evaluatedAt: evaluatedAt,
2030
+ useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
2025
2031
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
2026
2032
  });
2027
2033
  var candidateGroupMap = new Map(candidateGroups.map(function (group) {
@@ -2222,6 +2228,7 @@ export function validateAvailabilitySelection(projection, params) {
2222
2228
  projection: projection,
2223
2229
  evaluatedAt: evaluatedAt,
2224
2230
  requirementSelections: params.requirementSelections,
2231
+ useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
2225
2232
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
2226
2233
  })
2227
2234
  });
@@ -250,6 +250,13 @@ export interface GetProductTimeRangesRequest {
250
250
  }
251
251
  export interface GetProductTimeRangesRuntimeOptions {
252
252
  evaluatedAt?: string;
253
+ /**
254
+ * Internal POS capability: fixed-duration candidates start from the stable
255
+ * context anchor's current minute instead of rounding up to ten minutes, and
256
+ * that minute remains selectable during before-start cutoff evaluation.
257
+ * Other callers keep the legacy alignment and strict second-level cutoff.
258
+ */
259
+ useExactDurationCandidateMinute?: boolean;
253
260
  /**
254
261
  * Internal POS capability: allow explicit duration/start overrides to append
255
262
  * a custom duration candidate for Session products. Fixed Session ranges are
@@ -4293,6 +4293,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4293
4293
  allowOutsideOperatingHoursForRequestedStartTimes: true
4294
4294
  } : {}), {
4295
4295
  evaluatedAt: this.getAvailabilityRuntimeDateTime(),
4296
+ useExactDurationCandidateMinute: isPosAvailabilityRequest,
4296
4297
  allowSessionCustomRanges: isPosAvailabilityRequest,
4297
4298
  allowExcludedScheduleDateOverride: isPosAvailabilityRequest
4298
4299
  }).map(function (group) {
@@ -4332,6 +4333,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4332
4333
  this.assertContextualQueryFreshness(context, request);
4333
4334
  isPosAvailabilityRequest = String((_this$otherParams$pla2 = (_this$otherParams19 = this.otherParams) === null || _this$otherParams19 === void 0 ? void 0 : _this$otherParams19.platform) !== null && _this$otherParams$pla2 !== void 0 ? _this$otherParams$pla2 : '').trim().toLowerCase() === 'pos';
4334
4335
  result = queryAvailabilityProjection(projectionEntry.projection, request, {
4336
+ useExactDurationCandidateMinute: isPosAvailabilityRequest,
4335
4337
  allowExcludedScheduleDateOverride: isPosAvailabilityRequest
4336
4338
  });
4337
4339
  contextVersion = context.activeVersion;
@@ -4686,6 +4688,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4686
4688
  }, allowPosAvailabilityOverride ? {
4687
4689
  allowOutsideOperatingHoursForRequestedStartTimes: true
4688
4690
  } : {}) : {}) : {}), {
4691
+ useExactDurationCandidateMinute: allowPosAvailabilityOverride,
4689
4692
  allowSessionCustomRanges: allowPosAvailabilityOverride,
4690
4693
  allowExcludedScheduleDateOverride: allowPosAvailabilityOverride
4691
4694
  }).flatMap(function (group) {
@@ -4721,6 +4724,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4721
4724
  partySize: partySize,
4722
4725
  bookingCount: bookingCount
4723
4726
  }, {
4727
+ useExactDurationCandidateMinute: allowPosAvailabilityOverride,
4724
4728
  allowExcludedScheduleDateOverride: allowPosAvailabilityOverride
4725
4729
  });
4726
4730
  if (allowPosAvailabilityOverride && !validation.ok && validation.conflicts.every(function (conflict) {
@@ -281,10 +281,12 @@ function evaluateCandidateTimeGate(params) {
281
281
  };
282
282
  }
283
283
  if (policy.type === 'before_start') {
284
- // Flexible-duration candidates start at minute precision. Keep the current
285
- // minute selectable instead of treating the freshly generated candidate as
286
- // already started because the query clock still contains seconds.
287
- const hasNotReachedStart = product.isFlexibleDuration ? floorToMinute(now) <= candidateRange.start : now < candidateRange.start;
284
+ // Flexible-duration candidates and POS fixed-duration anchors start at
285
+ // minute precision. Keep that current minute selectable instead of treating
286
+ // the freshly generated candidate as already started because the query
287
+ // clock still contains seconds.
288
+ const usesMinutePrecision = product.isFlexibleDuration || evaluationContext.useExactDurationCandidateMinute && product.kind === 'duration';
289
+ const hasNotReachedStart = usesMinutePrecision ? floorToMinute(now) <= candidateRange.start : now < candidateRange.start;
288
290
  if (hasNotReachedStart) return null;
289
291
  return {
290
292
  status: 'unavailable',
@@ -1050,7 +1052,8 @@ function getProductTimeRanges(projection, request = {}, runtimeOptions = {}) {
1050
1052
  }
1051
1053
  return floorToMinute(evaluatedAt);
1052
1054
  })();
1053
- const durationAnchor = ceilToTenMinutes(toDateTime(projection.meta.durationCandidateAnchorAt, projection.meta.timezone), projection.meta.timezone);
1055
+ const durationCandidateAnchor = toDateTime(projection.meta.durationCandidateAnchorAt, projection.meta.timezone);
1056
+ const durationAnchor = runtimeOptions.useExactDurationCandidateMinute ? floorToMinute(durationCandidateAnchor) : ceilToTenMinutes(durationCandidateAnchor, projection.meta.timezone);
1054
1057
  const requestedStartTimes = resolveRequestedDurationStartTimes(product, request);
1055
1058
  const ranges = [];
1056
1059
  baseRanges.forEach(range => {
@@ -1256,6 +1259,7 @@ function buildEvaluationContext(params) {
1256
1259
  evaluatedAtMs: evaluatedAt,
1257
1260
  resourceIdSet: params.resourceIds?.length ? new Set(params.resourceIds.map(String)) : null,
1258
1261
  selectionsByGroupKey,
1262
+ useExactDurationCandidateMinute: params.useExactDurationCandidateMinute === true,
1259
1263
  allowExcludedScheduleDateOverride: params.allowExcludedScheduleDateOverride === true
1260
1264
  };
1261
1265
  }
@@ -1663,6 +1667,7 @@ function queryAvailabilityProjection(projection, request, runtimeOptions = {}) {
1663
1667
  projection,
1664
1668
  evaluatedAt,
1665
1669
  resourceIds: request.resourceIds,
1670
+ useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
1666
1671
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
1667
1672
  });
1668
1673
  if (request.target === 'time') {
@@ -1738,6 +1743,7 @@ function queryAvailabilityProjection(projection, request, runtimeOptions = {}) {
1738
1743
  partySize: normalizedPartySize
1739
1744
  }, {
1740
1745
  evaluatedAt,
1746
+ useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
1741
1747
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
1742
1748
  });
1743
1749
  const candidateGroupMap = new Map(candidateGroups.map(group => [String(group.productId), group]));
@@ -1910,6 +1916,7 @@ function validateAvailabilitySelection(projection, params, runtimeOptions = {})
1910
1916
  projection,
1911
1917
  evaluatedAt,
1912
1918
  requirementSelections: params.requirementSelections,
1919
+ useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
1913
1920
  allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
1914
1921
  })
1915
1922
  });
@@ -250,6 +250,13 @@ export interface GetProductTimeRangesRequest {
250
250
  }
251
251
  export interface GetProductTimeRangesRuntimeOptions {
252
252
  evaluatedAt?: string;
253
+ /**
254
+ * Internal POS capability: fixed-duration candidates start from the stable
255
+ * context anchor's current minute instead of rounding up to ten minutes, and
256
+ * that minute remains selectable during before-start cutoff evaluation.
257
+ * Other callers keep the legacy alignment and strict second-level cutoff.
258
+ */
259
+ useExactDurationCandidateMinute?: boolean;
253
260
  /**
254
261
  * Internal POS capability: allow explicit duration/start overrides to append
255
262
  * a custom duration candidate for Session products. Fixed Session ranges are
@@ -2873,6 +2873,7 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
2873
2873
  } : {})
2874
2874
  }, {
2875
2875
  evaluatedAt: this.getAvailabilityRuntimeDateTime(),
2876
+ useExactDurationCandidateMinute: isPosAvailabilityRequest,
2876
2877
  allowSessionCustomRanges: isPosAvailabilityRequest,
2877
2878
  allowExcludedScheduleDateOverride: isPosAvailabilityRequest
2878
2879
  }).map(group => ({
@@ -2891,6 +2892,7 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
2891
2892
  this.assertContextualQueryFreshness(context, request);
2892
2893
  const isPosAvailabilityRequest = String(this.otherParams?.platform ?? '').trim().toLowerCase() === 'pos';
2893
2894
  const result = (0, _ResourcePlanner.queryAvailabilityProjection)(projectionEntry.projection, request, {
2895
+ useExactDurationCandidateMinute: isPosAvailabilityRequest,
2894
2896
  allowExcludedScheduleDateOverride: isPosAvailabilityRequest
2895
2897
  });
2896
2898
  const contextVersion = context.activeVersion;
@@ -3149,6 +3151,7 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
3149
3151
  } : {})
3150
3152
  } : {})
3151
3153
  }, {
3154
+ useExactDurationCandidateMinute: allowPosAvailabilityOverride,
3152
3155
  allowSessionCustomRanges: allowPosAvailabilityOverride,
3153
3156
  allowExcludedScheduleDateOverride: allowPosAvailabilityOverride
3154
3157
  }).flatMap(group => group.ranges);
@@ -3172,6 +3175,7 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
3172
3175
  partySize,
3173
3176
  bookingCount
3174
3177
  }, {
3178
+ useExactDurationCandidateMinute: allowPosAvailabilityOverride,
3175
3179
  allowExcludedScheduleDateOverride: allowPosAvailabilityOverride
3176
3180
  });
3177
3181
  if (allowPosAvailabilityOverride && !validation.ok && validation.conflicts.every(conflict => POS_OVERRIDABLE_AVAILABILITY_CONFLICT_CODES.has(conflict.code))) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "2.2.300",
4
+ "version": "2.2.301",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",