@pisell/pisellos 2.2.296 → 2.2.298

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.
@@ -62,13 +62,21 @@ function resolveRequestedDurationMinutes(product, request) {
62
62
  }
63
63
  function resolveRequestedDurationStartTimes(product, request) {
64
64
  var _request$durationStar;
65
- if (product.kind !== 'duration') return [];
65
+ var allowSessionCustomRanges = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
66
+ if (product.kind !== 'duration' && !(product.kind === 'session' && allowSessionCustomRanges)) return [];
66
67
  var values = (_request$durationStar = request.durationStartTimesByProductId) === null || _request$durationStar === void 0 ? void 0 : _request$durationStar[String(product.id)];
67
68
  if (!Array.isArray(values)) return [];
68
69
  return Array.from(new Set(values.filter(function (value) {
69
70
  return typeof value === 'string' && /^([01]\d|2[0-3]):[0-5]\d$/.test(value);
70
71
  })));
71
72
  }
73
+ function resolveRequestedSessionDurationMinutes(product, request, allowSessionCustomRanges) {
74
+ var _request$durationMinu2;
75
+ if (product.kind !== 'session' || !allowSessionCustomRanges) return undefined;
76
+ var override = (_request$durationMinu2 = request.durationMinutesByProductId) === null || _request$durationMinu2 === void 0 ? void 0 : _request$durationMinu2[String(product.id)];
77
+ var normalized = Number(override);
78
+ return Number.isInteger(normalized) && normalized > 0 ? normalized : undefined;
79
+ }
72
80
  function toDateTime(value, _timezoneName) {
73
81
  try {
74
82
  return localDateTimeToScalar(parseLocalDateTime(value));
@@ -212,7 +220,11 @@ function evaluateCandidateTimeGate(params) {
212
220
  };
213
221
  }
214
222
  if (policy.type === 'before_start') {
215
- if (now < candidateRange.start) return null;
223
+ // Flexible-duration candidates start at minute precision. Keep the current
224
+ // minute selectable instead of treating the freshly generated candidate as
225
+ // already started because the query clock still contains seconds.
226
+ var hasNotReachedStart = product.isFlexibleDuration ? floorToMinute(now) <= candidateRange.start : now < candidateRange.start;
227
+ if (hasNotReachedStart) return null;
216
228
  return {
217
229
  status: 'unavailable',
218
230
  reasonCodes: ['booking_cutoff_before_start'],
@@ -1025,12 +1037,23 @@ export function getProductTimeRanges(projection) {
1025
1037
  };
1026
1038
  }
1027
1039
  if (product.kind === 'session' || product.kind === 'venue_slot') {
1040
+ var fixedRanges = getSessionRangesForProduct(projection, product, dateRange);
1041
+ var customRanges = [];
1042
+ var customDurationMinutes = resolveRequestedSessionDurationMinutes(product, request, runtimeOptions.allowSessionCustomRanges === true);
1043
+ var _requestedStartTimes = resolveRequestedDurationStartTimes(product, request, runtimeOptions.allowSessionCustomRanges === true);
1044
+ if (product.kind === 'session' && customDurationMinutes && dateRange.startDate === dateRange.endDate) {
1045
+ _requestedStartTimes.forEach(function (startTime) {
1046
+ var start = toDateTimeInDate(dateRange.startDate, startTime, projection.meta.timezone);
1047
+ if (!Number.isFinite(start)) return;
1048
+ customRanges.push(createDurationTimeRange(product, start, customDurationMinutes, projection, fixedOffsetMinutes));
1049
+ });
1050
+ }
1028
1051
  return {
1029
1052
  productId: product.id,
1030
1053
  title: product.title,
1031
1054
  kind: product.kind,
1032
1055
  slotStepMinutes: slotStepMinutes,
1033
- ranges: getSessionRangesForProduct(projection, product, dateRange)
1056
+ ranges: dedupeProductRanges([].concat(_toConsumableArray(fixedRanges), customRanges))
1034
1057
  };
1035
1058
  }
1036
1059
  var requiredGroups = (product.requirementGroups || []).filter(function (group) {
@@ -243,6 +243,13 @@ export interface GetProductTimeRangesRequest {
243
243
  }
244
244
  export interface GetProductTimeRangesRuntimeOptions {
245
245
  evaluatedAt?: string;
246
+ /**
247
+ * Internal POS capability: allow explicit duration/start overrides to append
248
+ * a custom duration candidate for Session products. Fixed Session ranges are
249
+ * still returned unchanged. Callers outside the POS facade must leave this
250
+ * disabled.
251
+ */
252
+ allowSessionCustomRanges?: boolean;
246
253
  }
247
254
  export interface QueryAvailabilityBaseRequest {
248
255
  productIds?: AvailabilityId[];
@@ -1029,7 +1029,7 @@ function buildBookingFromAvailabilitySelection(params) {
1029
1029
  var timeSlotId = (_candidate$primarySch3 = (_candidate$primarySch4 = candidate.primaryScheduleRef) === null || _candidate$primarySch4 === void 0 ? void 0 : _candidate$primarySch4.timeSlotId) !== null && _candidate$primarySch3 !== void 0 ? _candidate$primarySch3 : (_assignments$find2 = assignments.find(function (assignment) {
1030
1030
  return assignment.timeSlotId != null;
1031
1031
  })) === null || _assignments$find2 === void 0 ? void 0 : _assignments$find2.timeSlotId;
1032
- if (product.kind === 'session' && scheduleId == null) {
1032
+ if (product.kind === 'session' && candidate.source === 'session_schedule' && scheduleId == null) {
1033
1033
  throw new AvailabilityError('REVALIDATION_FAILED', 'session 候选缺少真实 schedule identity', {
1034
1034
  productId: product.id,
1035
1035
  candidateKey: candidate.key,
@@ -1038,15 +1038,16 @@ function buildBookingFromAvailabilitySelection(params) {
1038
1038
  }
1039
1039
  var normalizedHolder = holder && _typeof(holder) === 'object' ? cloneDeep(holder) : undefined;
1040
1040
  var normalizedHolderIds = Array.isArray(holderIds) ? cloneDeep(holderIds) : holderIds;
1041
- return _objectSpread(_objectSpread({
1041
+ return _objectSpread(_objectSpread(_objectSpread({
1042
1042
  start_date: bookingStartAt.slice(0, 10),
1043
1043
  start_time: bookingStartAt.slice(11, 16),
1044
1044
  end_date: bookingEndAt.slice(0, 10),
1045
1045
  end_time: bookingEndAt.slice(11, 16),
1046
1046
  duration: Math.max(1, Math.trunc((endScalar - startScalar) / (60 * 1000))),
1047
- like_status: 'common',
1047
+ like_status: 'common'
1048
+ }, product.kind === 'session' && candidate.source === 'duration_window' ? {} : {
1048
1049
  schedule_id: scheduleId !== null && scheduleId !== void 0 ? scheduleId : 0
1049
- }, normalizedHolder ? {
1050
+ }), normalizedHolder ? {
1050
1051
  holder: normalizedHolder
1051
1052
  } : {}), {}, {
1052
1053
  resources: assignments.map(function (assignment) {
@@ -4209,6 +4210,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4209
4210
  context,
4210
4211
  projectionEntry,
4211
4212
  contextVersion,
4213
+ isPosAvailabilityRequest,
4212
4214
  allowOutsideOperatingHoursForRequestedStartTimes,
4213
4215
  _args35 = arguments;
4214
4216
  return _regeneratorRuntime().wrap(function _callee35$(_context35) {
@@ -4222,13 +4224,15 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4222
4224
  context = _yield$this$ensureAva.context;
4223
4225
  projectionEntry = _yield$this$ensureAva.projectionEntry;
4224
4226
  contextVersion = context.activeVersion;
4225
- allowOutsideOperatingHoursForRequestedStartTimes = String((_this$otherParams$pla = (_this$otherParams18 = this.otherParams) === null || _this$otherParams18 === void 0 ? void 0 : _this$otherParams18.platform) !== null && _this$otherParams$pla !== void 0 ? _this$otherParams$pla : '').trim().toLowerCase() === 'pos' && Object.values(request.durationStartTimesByProductId || {}).some(function (startTimes) {
4227
+ isPosAvailabilityRequest = String((_this$otherParams$pla = (_this$otherParams18 = this.otherParams) === null || _this$otherParams18 === void 0 ? void 0 : _this$otherParams18.platform) !== null && _this$otherParams$pla !== void 0 ? _this$otherParams$pla : '').trim().toLowerCase() === 'pos';
4228
+ allowOutsideOperatingHoursForRequestedStartTimes = isPosAvailabilityRequest && Object.values(request.durationStartTimesByProductId || {}).some(function (startTimes) {
4226
4229
  return Array.isArray(startTimes) && startTimes.length > 0;
4227
4230
  });
4228
4231
  return _context35.abrupt("return", getProjectionProductTimeRanges(projectionEntry.projection, _objectSpread(_objectSpread({}, request), allowOutsideOperatingHoursForRequestedStartTimes ? {
4229
4232
  allowOutsideOperatingHoursForRequestedStartTimes: true
4230
4233
  } : {}), {
4231
- evaluatedAt: this.getAvailabilityRuntimeDateTime()
4234
+ evaluatedAt: this.getAvailabilityRuntimeDateTime(),
4235
+ allowSessionCustomRanges: isPosAvailabilityRequest
4232
4236
  }).map(function (group) {
4233
4237
  return _objectSpread(_objectSpread({}, group), {}, {
4234
4238
  ranges: group.ranges.map(function (candidate) {
@@ -4236,7 +4240,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4236
4240
  })
4237
4241
  });
4238
4242
  }));
4239
- case 9:
4243
+ case 10:
4240
4244
  case "end":
4241
4245
  return _context35.stop();
4242
4246
  }
@@ -4615,7 +4619,9 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
4615
4619
  durationStartTimesByProductId: _defineProperty({}, String(params.candidate.productId), [candidateStartTime])
4616
4620
  }, allowPosAvailabilityOverride ? {
4617
4621
  allowOutsideOperatingHoursForRequestedStartTimes: true
4618
- } : {}) : {}) : {})).flatMap(function (group) {
4622
+ } : {}) : {}) : {}), {
4623
+ allowSessionCustomRanges: allowPosAvailabilityOverride
4624
+ }).flatMap(function (group) {
4619
4625
  return group.ranges;
4620
4626
  });
4621
4627
  refreshedCandidateBase = refreshedRanges.find(function (candidate) {
@@ -1 +1,46 @@
1
- "use strict";
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "BUY_X_GET_Y_FREE_STRATEGY", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _examples.BUY_X_GET_Y_FREE_STRATEGY;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "ITEM_REWARD_STRATEGY", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _examples.ITEM_REWARD_STRATEGY;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "PromotionAdapter", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _adapter.PromotionAdapter;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "PromotionEvaluator", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _evaluator.PromotionEvaluator;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "X_ITEMS_FOR_Y_PRICE_STRATEGY", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _examples.X_ITEMS_FOR_Y_PRICE_STRATEGY;
34
+ }
35
+ });
36
+ Object.defineProperty(exports, "default", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _adapter.default;
40
+ }
41
+ });
42
+ var _evaluator = require("./evaluator");
43
+ var _adapter = _interopRequireWildcard(require("./adapter"));
44
+ var _examples = require("./examples");
45
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
46
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
@@ -55,12 +55,18 @@ function resolveRequestedDurationMinutes(product, request) {
55
55
  const normalized = Number(override);
56
56
  return Number.isInteger(normalized) && normalized > 0 ? normalized : configured;
57
57
  }
58
- function resolveRequestedDurationStartTimes(product, request) {
59
- if (product.kind !== 'duration') return [];
58
+ function resolveRequestedDurationStartTimes(product, request, allowSessionCustomRanges = false) {
59
+ if (product.kind !== 'duration' && !(product.kind === 'session' && allowSessionCustomRanges)) return [];
60
60
  const values = request.durationStartTimesByProductId?.[String(product.id)];
61
61
  if (!Array.isArray(values)) return [];
62
62
  return Array.from(new Set(values.filter(value => typeof value === 'string' && /^([01]\d|2[0-3]):[0-5]\d$/.test(value))));
63
63
  }
64
+ function resolveRequestedSessionDurationMinutes(product, request, allowSessionCustomRanges) {
65
+ if (product.kind !== 'session' || !allowSessionCustomRanges) return undefined;
66
+ const override = request.durationMinutesByProductId?.[String(product.id)];
67
+ const normalized = Number(override);
68
+ return Number.isInteger(normalized) && normalized > 0 ? normalized : undefined;
69
+ }
64
70
  function toDateTime(value, _timezoneName) {
65
71
  try {
66
72
  return (0, _localClock.localDateTimeToScalar)((0, _localClock.parseLocalDateTime)(value));
@@ -207,7 +213,11 @@ function evaluateCandidateTimeGate(params) {
207
213
  };
208
214
  }
209
215
  if (policy.type === 'before_start') {
210
- if (now < candidateRange.start) return null;
216
+ // Flexible-duration candidates start at minute precision. Keep the current
217
+ // minute selectable instead of treating the freshly generated candidate as
218
+ // already started because the query clock still contains seconds.
219
+ const hasNotReachedStart = product.isFlexibleDuration ? floorToMinute(now) <= candidateRange.start : now < candidateRange.start;
220
+ if (hasNotReachedStart) return null;
211
221
  return {
212
222
  status: 'unavailable',
213
223
  reasonCodes: ['booking_cutoff_before_start'],
@@ -919,12 +929,23 @@ function getProductTimeRanges(projection, request = {}, runtimeOptions = {}) {
919
929
  };
920
930
  }
921
931
  if (product.kind === 'session' || product.kind === 'venue_slot') {
932
+ const fixedRanges = getSessionRangesForProduct(projection, product, dateRange);
933
+ const customRanges = [];
934
+ const customDurationMinutes = resolveRequestedSessionDurationMinutes(product, request, runtimeOptions.allowSessionCustomRanges === true);
935
+ const requestedStartTimes = resolveRequestedDurationStartTimes(product, request, runtimeOptions.allowSessionCustomRanges === true);
936
+ if (product.kind === 'session' && customDurationMinutes && dateRange.startDate === dateRange.endDate) {
937
+ requestedStartTimes.forEach(startTime => {
938
+ const start = toDateTimeInDate(dateRange.startDate, startTime, projection.meta.timezone);
939
+ if (!Number.isFinite(start)) return;
940
+ customRanges.push(createDurationTimeRange(product, start, customDurationMinutes, projection, fixedOffsetMinutes));
941
+ });
942
+ }
922
943
  return {
923
944
  productId: product.id,
924
945
  title: product.title,
925
946
  kind: product.kind,
926
947
  slotStepMinutes,
927
- ranges: getSessionRangesForProduct(projection, product, dateRange)
948
+ ranges: dedupeProductRanges([...fixedRanges, ...customRanges])
928
949
  };
929
950
  }
930
951
  const requiredGroups = (product.requirementGroups || []).filter(group => group.required !== false);
@@ -243,6 +243,13 @@ export interface GetProductTimeRangesRequest {
243
243
  }
244
244
  export interface GetProductTimeRangesRuntimeOptions {
245
245
  evaluatedAt?: string;
246
+ /**
247
+ * Internal POS capability: allow explicit duration/start overrides to append
248
+ * a custom duration candidate for Session products. Fixed Session ranges are
249
+ * still returned unchanged. Callers outside the POS facade must leave this
250
+ * disabled.
251
+ */
252
+ allowSessionCustomRanges?: boolean;
246
253
  }
247
254
  export interface QueryAvailabilityBaseRequest {
248
255
  productIds?: AvailabilityId[];
@@ -945,7 +945,7 @@ function buildBookingFromAvailabilitySelection(params) {
945
945
  const endScalar = (0, _localClock.localDateTimeToScalar)((0, _localClock.parseLocalDateTime)(bookingEndAt));
946
946
  const scheduleId = candidate.primaryScheduleRef?.scheduleId ?? assignments.find(assignment => assignment.scheduleId != null)?.scheduleId;
947
947
  const timeSlotId = candidate.primaryScheduleRef?.timeSlotId ?? assignments.find(assignment => assignment.timeSlotId != null)?.timeSlotId;
948
- if (product.kind === 'session' && scheduleId == null) {
948
+ if (product.kind === 'session' && candidate.source === 'session_schedule' && scheduleId == null) {
949
949
  throw new _ResourcePlanner.AvailabilityError('REVALIDATION_FAILED', 'session 候选缺少真实 schedule identity', {
950
950
  productId: product.id,
951
951
  candidateKey: candidate.key,
@@ -961,7 +961,9 @@ function buildBookingFromAvailabilitySelection(params) {
961
961
  end_time: bookingEndAt.slice(11, 16),
962
962
  duration: Math.max(1, Math.trunc((endScalar - startScalar) / (60 * 1000))),
963
963
  like_status: 'common',
964
- schedule_id: scheduleId ?? 0,
964
+ ...(product.kind === 'session' && candidate.source === 'duration_window' ? {} : {
965
+ schedule_id: scheduleId ?? 0
966
+ }),
965
967
  ...(normalizedHolder ? {
966
968
  holder: normalizedHolder
967
969
  } : {}),
@@ -2809,14 +2811,16 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
2809
2811
  projectionEntry
2810
2812
  } = await this.ensureAvailabilityContextProjection(contextId, 'get_product_time_ranges');
2811
2813
  const contextVersion = context.activeVersion;
2812
- const allowOutsideOperatingHoursForRequestedStartTimes = String(this.otherParams?.platform ?? '').trim().toLowerCase() === 'pos' && Object.values(request.durationStartTimesByProductId || {}).some(startTimes => Array.isArray(startTimes) && startTimes.length > 0);
2814
+ const isPosAvailabilityRequest = String(this.otherParams?.platform ?? '').trim().toLowerCase() === 'pos';
2815
+ const allowOutsideOperatingHoursForRequestedStartTimes = isPosAvailabilityRequest && Object.values(request.durationStartTimesByProductId || {}).some(startTimes => Array.isArray(startTimes) && startTimes.length > 0);
2813
2816
  return (0, _ResourcePlanner.getProductTimeRanges)(projectionEntry.projection, {
2814
2817
  ...request,
2815
2818
  ...(allowOutsideOperatingHoursForRequestedStartTimes ? {
2816
2819
  allowOutsideOperatingHoursForRequestedStartTimes: true
2817
2820
  } : {})
2818
2821
  }, {
2819
- evaluatedAt: this.getAvailabilityRuntimeDateTime()
2822
+ evaluatedAt: this.getAvailabilityRuntimeDateTime(),
2823
+ allowSessionCustomRanges: isPosAvailabilityRequest
2820
2824
  }).map(group => ({
2821
2825
  ...group,
2822
2826
  ranges: group.ranges.map(candidate => this.decorateAvailabilityCandidate(context.contextId, contextVersion, candidate))
@@ -3087,6 +3091,8 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
3087
3091
  } : {})
3088
3092
  } : {})
3089
3093
  } : {})
3094
+ }, {
3095
+ allowSessionCustomRanges: allowPosAvailabilityOverride
3090
3096
  }).flatMap(group => group.ranges);
3091
3097
  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);
3092
3098
  if (!refreshedCandidateBase) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "2.2.296",
4
+ "version": "2.2.298",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",