@pisell/pisellos 2.3.144 → 2.3.145
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.
- package/dist/modules/BookingContext/utils/productExtend.d.ts +7 -0
- package/dist/modules/BookingContext/utils/productExtend.js +62 -18
- package/dist/modules/Order/index.d.ts +1 -0
- package/dist/modules/Order/index.js +380 -198
- package/dist/modules/Order/types.d.ts +9 -0
- package/dist/modules/ResourcePlanner/planner.d.ts +2 -0
- package/dist/modules/ResourcePlanner/planner.js +327 -22
- package/dist/modules/ResourcePlanner/types.d.ts +29 -0
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
- package/dist/solution/BookingTicket/utils/addProductDecision.js +1 -1
- package/dist/solution/UnifiedBookingSales/index.d.ts +3 -0
- package/dist/solution/UnifiedBookingSales/index.js +432 -163
- package/dist/solution/UnifiedBookingSales/types.d.ts +14 -2
- package/lib/model/strategy/adapter/promotion/index.js +46 -1
- package/lib/modules/BookingContext/utils/productExtend.d.ts +7 -0
- package/lib/modules/BookingContext/utils/productExtend.js +45 -2
- package/lib/modules/Order/index.d.ts +1 -0
- package/lib/modules/Order/index.js +92 -10
- package/lib/modules/Order/types.d.ts +9 -0
- package/lib/modules/ResourcePlanner/planner.d.ts +2 -0
- package/lib/modules/ResourcePlanner/planner.js +247 -7
- package/lib/modules/ResourcePlanner/types.d.ts +29 -0
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
- package/lib/solution/BookingTicket/utils/addProductDecision.js +1 -1
- package/lib/solution/UnifiedBookingSales/index.d.ts +3 -0
- package/lib/solution/UnifiedBookingSales/index.js +220 -27
- package/lib/solution/UnifiedBookingSales/types.d.ts +14 -2
- package/package.json +1 -1
|
@@ -445,6 +445,15 @@ export interface AddProductToOrderOptions {
|
|
|
445
445
|
disableMerge?: boolean;
|
|
446
446
|
/** 商品行 UID 落定后,由 OrderModule 原子绑定到该行的 Sales Notes 草稿。 */
|
|
447
447
|
salesNotes?: SalesNoteDraftInput[];
|
|
448
|
+
/**
|
|
449
|
+
* 自动预约加购的同步提交门禁;抛错时不发布本次新增。
|
|
450
|
+
* 带门禁时先在私有草稿中准备全部商品/booking,异步等待后及原子发布前重新调用。
|
|
451
|
+
* 门禁须校验当前订单身份/版本和真实时间;发布前不会因本次拆行改变订单版本。
|
|
452
|
+
* 不传时保留原有人工加购行为。
|
|
453
|
+
*/
|
|
454
|
+
availabilityCommitGuard?: () => void;
|
|
455
|
+
/** 发布后的订单/业务归属检查;只用于阻止旧异步收尾写入新单,不再校验截止或 revision。 */
|
|
456
|
+
availabilityCommitTargetGuard?: () => boolean;
|
|
448
457
|
}
|
|
449
458
|
/**
|
|
450
459
|
* 删除商品后的可选位置保持策略。
|
|
@@ -1,5 +1,7 @@
|
|
|
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
|
+
/** Resolve the label without changing the real calendar timestamp. */
|
|
4
|
+
export declare function getDurationBusinessDate(projection: AvailabilityProjection, startAt: string): string;
|
|
3
5
|
export declare function getProductTimeRanges(projection: AvailabilityProjection, request?: GetProductTimeRangesRequest, runtimeOptions?: GetProductTimeRangesRuntimeOptions): ProductTimeRangeGroup[];
|
|
4
6
|
export declare function queryAvailabilityProjection(projection: AvailabilityProjection, request: AvailabilityQuery, runtimeOptions?: GetProductTimeRangesRuntimeOptions): AvailabilityQueryResult;
|
|
5
7
|
export declare function validateAvailabilitySelection(projection: AvailabilityProjection, params: AvailabilitySelectionValidationParams, runtimeOptions?: GetProductTimeRangesRuntimeOptions): AvailabilitySelectionValidationResult;
|
|
@@ -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); }
|
|
@@ -263,6 +267,18 @@ function evaluateCandidateTimeGate(params) {
|
|
|
263
267
|
};
|
|
264
268
|
}
|
|
265
269
|
var policy = product.cutOffPolicy;
|
|
270
|
+
// Current duration items can be shown outside business hours. Their real
|
|
271
|
+
// interval must remain unavailable, including products with no resource groups.
|
|
272
|
+
if (evaluationContext.useDurationTimeGrid && product.kind === 'duration' && !projection.meta.defaults.operatingHours.windows.some(function (window) {
|
|
273
|
+
var range = normalizeAbsoluteRange(window);
|
|
274
|
+
return range && contains(range, candidateRange);
|
|
275
|
+
})) {
|
|
276
|
+
return {
|
|
277
|
+
status: 'unavailable',
|
|
278
|
+
reasonCodes: ['outside_operating_hours'],
|
|
279
|
+
conflictCode: 'booking_cutoff'
|
|
280
|
+
};
|
|
281
|
+
}
|
|
266
282
|
if (!policy) return null;
|
|
267
283
|
if (resolveCutOffPolicyIssue(policy)) {
|
|
268
284
|
return {
|
|
@@ -299,8 +315,8 @@ function evaluateCandidateTimeGate(params) {
|
|
|
299
315
|
// otherwise a minute refresh turns it into 0 capacity and incorrectly
|
|
300
316
|
// advances a create flow to the next slot. The earlier `past` gate still
|
|
301
317
|
// 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';
|
|
318
|
+
var isActivePosDurationAnchor = evaluationContext.useExactDurationCandidateMinute && !evaluationContext.enforceSaleCutoff && product.kind === 'duration' && !product.isFlexibleDuration && evaluationContext.durationCandidateAnchorAtMs === candidateRange.start;
|
|
319
|
+
var usesMinutePrecision = product.isFlexibleDuration || evaluationContext.useDurationTimeGrid || evaluationContext.useExactDurationCandidateMinute && product.kind === 'duration';
|
|
304
320
|
var hasNotReachedStart = isActivePosDurationAnchor || (usesMinutePrecision ? floorToMinute(now) <= candidateRange.start : now < candidateRange.start);
|
|
305
321
|
if (hasNotReachedStart) return null;
|
|
306
322
|
return {
|
|
@@ -494,7 +510,7 @@ function normalizeResources(resources) {
|
|
|
494
510
|
});
|
|
495
511
|
}
|
|
496
512
|
function normalizeOperatingHours(params) {
|
|
497
|
-
var _params$input, _params$input2, _params$input3, _params$input4;
|
|
513
|
+
var _params$input, _params$input2, _params$input3, _params$input4, _params$input5, _params$input6;
|
|
498
514
|
var fallbackWindows = enumerateDates(params.dateRange.startDate, params.dateRange.endDate).map(function (date) {
|
|
499
515
|
var start = toDateTimeInDate(date, params.businessHours.startTime, params.timezoneName);
|
|
500
516
|
var end = toDateTimeInDate(date, params.businessHours.endTime, params.timezoneName);
|
|
@@ -530,11 +546,43 @@ function normalizeOperatingHours(params) {
|
|
|
530
546
|
};
|
|
531
547
|
var windows = normalizeWindows(sourceWindows);
|
|
532
548
|
var excludedWindows = normalizeWindows(((_params$input = params.input) === null || _params$input === void 0 ? void 0 : _params$input.excludedWindows) || []);
|
|
549
|
+
// Keep original dates and opening anchors separately: the availability
|
|
550
|
+
// windows below may be clipped at midnight or merged without segment identity.
|
|
551
|
+
var periodMap = new Map();
|
|
552
|
+
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) {
|
|
553
|
+
return {
|
|
554
|
+
businessDate: window.businessDate || window.startAt.slice(0, 10),
|
|
555
|
+
startAt: window.openingAnchorAt || window.startAt,
|
|
556
|
+
endAt: window.endAt
|
|
557
|
+
};
|
|
558
|
+
});
|
|
559
|
+
originalPeriods.forEach(function (period) {
|
|
560
|
+
var range = normalizeAbsoluteRange(period);
|
|
561
|
+
if (!range) return;
|
|
562
|
+
var previous = periodMap.get(period.businessDate);
|
|
563
|
+
periodMap.set(period.businessDate, {
|
|
564
|
+
start: previous ? Math.min(previous.start, range.start) : range.start,
|
|
565
|
+
end: previous ? Math.max(previous.end, range.end) : range.end
|
|
566
|
+
});
|
|
567
|
+
});
|
|
568
|
+
var businessPeriods = Array.from(periodMap, function (_ref) {
|
|
569
|
+
var _ref2 = _slicedToArray(_ref, 2),
|
|
570
|
+
businessDate = _ref2[0],
|
|
571
|
+
range = _ref2[1];
|
|
572
|
+
return {
|
|
573
|
+
businessDate: businessDate,
|
|
574
|
+
startAt: formatDateTime(range.start, params.timezoneName, params.fixedOffsetMinutes),
|
|
575
|
+
endAt: formatDateTime(range.end, params.timezoneName, params.fixedOffsetMinutes)
|
|
576
|
+
};
|
|
577
|
+
}).sort(function (left, right) {
|
|
578
|
+
return left.startAt.localeCompare(right.startAt);
|
|
579
|
+
});
|
|
533
580
|
return _objectSpread({
|
|
534
|
-
source: ((_params$
|
|
535
|
-
scheduleIds: uniqById(((_params$
|
|
536
|
-
missingScheduleIds: uniqById(((_params$
|
|
537
|
-
windows: windows
|
|
581
|
+
source: ((_params$input4 = params.input) === null || _params$input4 === void 0 ? void 0 : _params$input4.source) || params.fallbackSource,
|
|
582
|
+
scheduleIds: uniqById(((_params$input5 = params.input) === null || _params$input5 === void 0 ? void 0 : _params$input5.scheduleIds) || []),
|
|
583
|
+
missingScheduleIds: uniqById(((_params$input6 = params.input) === null || _params$input6 === void 0 ? void 0 : _params$input6.missingScheduleIds) || []),
|
|
584
|
+
windows: windows,
|
|
585
|
+
businessPeriods: businessPeriods
|
|
538
586
|
}, excludedWindows.length > 0 ? {
|
|
539
587
|
excludedWindows: excludedWindows
|
|
540
588
|
} : {});
|
|
@@ -553,8 +601,8 @@ function matchesRequirementGroup(requirementGroup, resource, product) {
|
|
|
553
601
|
return resource.capacity >= resolveRequiredCapacity(requirementGroup, product, partySize);
|
|
554
602
|
}
|
|
555
603
|
function resolveRequiredCapacity(requirementGroup, product, partySize) {
|
|
556
|
-
var
|
|
557
|
-
return Math.max(1, Number((
|
|
604
|
+
var _ref3, _ref4;
|
|
605
|
+
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
606
|
}
|
|
559
607
|
function buildCellKey(params) {
|
|
560
608
|
return [String(params.productId), params.groupId, String(params.resourceId), params.start, params.end].join(':');
|
|
@@ -608,8 +656,8 @@ function buildCells(projection) {
|
|
|
608
656
|
boundaries.add(window.start);
|
|
609
657
|
boundaries.add(window.end);
|
|
610
658
|
});
|
|
611
|
-
occupancies.forEach(function (
|
|
612
|
-
var range =
|
|
659
|
+
occupancies.forEach(function (_ref5) {
|
|
660
|
+
var range = _ref5.range;
|
|
613
661
|
boundaries.add(range.start);
|
|
614
662
|
boundaries.add(range.end);
|
|
615
663
|
});
|
|
@@ -627,11 +675,11 @@ function buildCells(projection) {
|
|
|
627
675
|
var isInsideWorkingWindow = windows.some(function (window) {
|
|
628
676
|
return contains(window, segment);
|
|
629
677
|
});
|
|
630
|
-
var segmentOccupancies = isInsideWorkingWindow ? occupancies.filter(function (
|
|
631
|
-
var range =
|
|
678
|
+
var segmentOccupancies = isInsideWorkingWindow ? occupancies.filter(function (_ref6) {
|
|
679
|
+
var range = _ref6.range;
|
|
632
680
|
return overlaps(range, segment);
|
|
633
|
-
}).map(function (
|
|
634
|
-
var occupancy =
|
|
681
|
+
}).map(function (_ref7) {
|
|
682
|
+
var occupancy = _ref7.occupancy;
|
|
635
683
|
return occupancy;
|
|
636
684
|
}) : [];
|
|
637
685
|
var usedCapacity = segmentOccupancies.reduce(function (sum, occupancy) {
|
|
@@ -1108,6 +1156,211 @@ function createDurationTimeRangeWithEnd(product, start, bookingEnd, projection,
|
|
|
1108
1156
|
scheduleRefs: []
|
|
1109
1157
|
};
|
|
1110
1158
|
}
|
|
1159
|
+
|
|
1160
|
+
/** Resolve the label without changing the real calendar timestamp. */
|
|
1161
|
+
export function getDurationBusinessDate(projection, startAt) {
|
|
1162
|
+
var start = toDateTime(startAt);
|
|
1163
|
+
var periods = projection.meta.defaults.operatingHours.businessPeriods || [];
|
|
1164
|
+
var period = _toConsumableArray(periods).reverse().find(function (item) {
|
|
1165
|
+
var range = normalizeAbsoluteRange(item);
|
|
1166
|
+
return range && range.start <= start && start < range.end;
|
|
1167
|
+
});
|
|
1168
|
+
return (period === null || period === void 0 ? void 0 : period.businessDate) || startAt.slice(0, 10);
|
|
1169
|
+
}
|
|
1170
|
+
function getAlignedDurationRanges(params) {
|
|
1171
|
+
var _request$rememberedSt, _request$editingStart;
|
|
1172
|
+
var projection = params.projection,
|
|
1173
|
+
product = params.product,
|
|
1174
|
+
request = params.request,
|
|
1175
|
+
runtimeOptions = params.runtimeOptions,
|
|
1176
|
+
dateRange = params.dateRange,
|
|
1177
|
+
operatingRanges = params.operatingRanges,
|
|
1178
|
+
baseRanges = params.baseRanges,
|
|
1179
|
+
resourceWindowIndex = params.resourceWindowIndex,
|
|
1180
|
+
fixedOffsetMinutes = params.fixedOffsetMinutes;
|
|
1181
|
+
var step = projection.meta.defaults.slotStepMinutes;
|
|
1182
|
+
var now = floorToMinute(toDateTime(runtimeOptions.evaluatedAt || projection.meta.durationCandidateAnchorAt));
|
|
1183
|
+
if (!Number.isFinite(now)) throw availabilityError('INVALID_TARGET_FILTER', 'evaluatedAt 必须是有效时间');
|
|
1184
|
+
var nowAt = formatDateTime(now, projection.meta.timezone, fixedOffsetMinutes);
|
|
1185
|
+
var currentBusinessDate = getDurationBusinessDate(projection, nowAt);
|
|
1186
|
+
var inRequestedDays = function inRequestedDays(date) {
|
|
1187
|
+
return date >= dateRange.startDate && date <= dateRange.endDate;
|
|
1188
|
+
};
|
|
1189
|
+
var periods = (projection.meta.defaults.operatingHours.businessPeriods || []).filter(function (period) {
|
|
1190
|
+
return inRequestedDays(period.businessDate);
|
|
1191
|
+
});
|
|
1192
|
+
// A prepared month includes tomorrow's windows too; the single-day UI must
|
|
1193
|
+
// receive the selected business cycle's end, not tomorrow's closing time.
|
|
1194
|
+
var operatingEndAt = dateRange.startDate === dateRange.endDate && periods.length ? periods.reduce(function (latest, period) {
|
|
1195
|
+
return period.endAt > latest ? period.endAt : latest;
|
|
1196
|
+
}, periods[0].endAt) : undefined;
|
|
1197
|
+
var ranges = [];
|
|
1198
|
+
var duration = resolveRequestedDurationMinutes(product, request);
|
|
1199
|
+
var addRange = function addRange(start, end, businessDate) {
|
|
1200
|
+
if (end <= start) return;
|
|
1201
|
+
var candidate = createDurationTimeRangeWithEnd(product, start, end, projection, fixedOffsetMinutes);
|
|
1202
|
+
candidate.businessDate = businessDate || getDurationBusinessDate(projection, candidate.startAt);
|
|
1203
|
+
if (inRequestedDays(candidate.businessDate)) ranges.push(candidate);
|
|
1204
|
+
};
|
|
1205
|
+
// A flexible end comes from resources that actually cover this exact start,
|
|
1206
|
+
// never from the next future window. Keep alternative real ends separate.
|
|
1207
|
+
var flexibleEnds = function flexibleEnds(start) {
|
|
1208
|
+
var _projection$meta$defa;
|
|
1209
|
+
var operating = operatingRanges.find(function (range) {
|
|
1210
|
+
return range.start <= start && start < range.end;
|
|
1211
|
+
});
|
|
1212
|
+
if (!operating) return [];
|
|
1213
|
+
var businessDate = getDurationBusinessDate(projection, formatDateTime(start, projection.meta.timezone, fixedOffsetMinutes));
|
|
1214
|
+
var period = (_projection$meta$defa = projection.meta.defaults.operatingHours.businessPeriods) === null || _projection$meta$defa === void 0 ? void 0 : _projection$meta$defa.find(function (item) {
|
|
1215
|
+
return item.businessDate === businessDate;
|
|
1216
|
+
});
|
|
1217
|
+
var operatingEnd = Math.min(operating.end, period ? toDateTime(period.endAt) : operating.end);
|
|
1218
|
+
var requiredGroups = (product.requirementGroups || []).filter(function (group) {
|
|
1219
|
+
return group.required !== false;
|
|
1220
|
+
});
|
|
1221
|
+
var groups = requiredGroups.map(function (group) {
|
|
1222
|
+
return projection.resources.filter(function (resource) {
|
|
1223
|
+
return matchesRequirementGroup(group, resource, product, request.partySize);
|
|
1224
|
+
}).filter(function (resource) {
|
|
1225
|
+
var _request$resourceIds;
|
|
1226
|
+
return !((_request$resourceIds = request.resourceIds) !== null && _request$resourceIds !== void 0 && _request$resourceIds.length) || request.resourceIds.some(function (id) {
|
|
1227
|
+
return sameId(id, resource.id);
|
|
1228
|
+
});
|
|
1229
|
+
}).flatMap(function (resource) {
|
|
1230
|
+
return (resourceWindowIndex.get(String(resource.id)) || []).filter(function (range) {
|
|
1231
|
+
return range.start <= start && start < range.end;
|
|
1232
|
+
}).map(function (range) {
|
|
1233
|
+
return Math.min(range.end, operatingEnd);
|
|
1234
|
+
});
|
|
1235
|
+
});
|
|
1236
|
+
});
|
|
1237
|
+
if (groups.some(function (ends) {
|
|
1238
|
+
return ends.length === 0;
|
|
1239
|
+
})) return [];
|
|
1240
|
+
if (!groups.length) return [operatingEnd];
|
|
1241
|
+
return Array.from(new Set(groups.flat())).filter(function (end) {
|
|
1242
|
+
return groups.every(function (ends) {
|
|
1243
|
+
return ends.some(function (availableEnd) {
|
|
1244
|
+
return availableEnd >= end;
|
|
1245
|
+
});
|
|
1246
|
+
});
|
|
1247
|
+
}).sort(function (left, right) {
|
|
1248
|
+
return left - right;
|
|
1249
|
+
});
|
|
1250
|
+
};
|
|
1251
|
+
if (product.isFlexibleDuration) {
|
|
1252
|
+
// Preserve the existing continuous-window UI, with the business-day label.
|
|
1253
|
+
periods.forEach(function (period) {
|
|
1254
|
+
var periodRange = normalizeAbsoluteRange(period);
|
|
1255
|
+
baseRanges.forEach(function (range) {
|
|
1256
|
+
var start = Math.max(range.start, periodRange.start, now);
|
|
1257
|
+
var end = Math.min(range.end, periodRange.end);
|
|
1258
|
+
if (start < end) addRange(start, end, period.businessDate);
|
|
1259
|
+
});
|
|
1260
|
+
});
|
|
1261
|
+
} else {
|
|
1262
|
+
periods.forEach(function (period) {
|
|
1263
|
+
var periodRange = normalizeAbsoluteRange(period);
|
|
1264
|
+
var anchor = 60 % step === 0 ? toDateStart(period.businessDate) : periodRange.start;
|
|
1265
|
+
baseRanges.forEach(function (range) {
|
|
1266
|
+
var lower = Math.max(range.start, periodRange.start, now);
|
|
1267
|
+
var upper = Math.min(range.end, periodRange.end);
|
|
1268
|
+
var cursor = anchor + Math.ceil((lower - anchor) / (step * 60000)) * step * 60000;
|
|
1269
|
+
for (; cursor + duration * 60000 <= upper; cursor += step * 60000) {
|
|
1270
|
+
addRange(cursor, cursor + duration * 60000, period.businessDate);
|
|
1271
|
+
}
|
|
1272
|
+
});
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
var unavailableCurrentTime;
|
|
1276
|
+
if (inRequestedDays(currentBusinessDate)) {
|
|
1277
|
+
if (product.isFlexibleDuration) {
|
|
1278
|
+
var ends = flexibleEnds(now);
|
|
1279
|
+
ends.forEach(function (end) {
|
|
1280
|
+
return addRange(now, end, currentBusinessDate);
|
|
1281
|
+
});
|
|
1282
|
+
if (!ends.length) {
|
|
1283
|
+
unavailableCurrentTime = {
|
|
1284
|
+
productId: product.id,
|
|
1285
|
+
startAt: nowAt,
|
|
1286
|
+
date: formatDate(now),
|
|
1287
|
+
businessDate: currentBusinessDate,
|
|
1288
|
+
startTime: formatTime(now),
|
|
1289
|
+
status: 'unavailable',
|
|
1290
|
+
reasonCodes: [operatingRanges.some(function (range) {
|
|
1291
|
+
return range.start <= now && now < range.end;
|
|
1292
|
+
}) ? 'outside_resource_window' : 'outside_operating_hours']
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1295
|
+
} else {
|
|
1296
|
+
// Even outside a working window the fixed product has a real end. Query
|
|
1297
|
+
// reports unavailable; POS manual capabilities remain a separate policy.
|
|
1298
|
+
addRange(now, now + duration * 60000, currentBusinessDate);
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
var rememberedAt = (_request$rememberedSt = request.rememberedStartAtByProductId) === null || _request$rememberedSt === void 0 ? void 0 : _request$rememberedSt[String(product.id)];
|
|
1302
|
+
if (rememberedAt !== undefined) {
|
|
1303
|
+
var start = toDateTime(rememberedAt);
|
|
1304
|
+
if (!Number.isFinite(start)) throw availabilityError('INVALID_TARGET_FILTER', '记忆开始时间必须是完整日期时间');
|
|
1305
|
+
if (product.isFlexibleDuration) {
|
|
1306
|
+
flexibleEnds(start).forEach(function (end) {
|
|
1307
|
+
return addRange(start, end);
|
|
1308
|
+
});
|
|
1309
|
+
} else {
|
|
1310
|
+
addRange(start, start + duration * 60000);
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
var editingAt = (_request$editingStart = request.editingStartAtByProductId) === null || _request$editingStart === void 0 ? void 0 : _request$editingStart[String(product.id)];
|
|
1314
|
+
if (editingAt !== undefined) {
|
|
1315
|
+
var _request$durationMinu3;
|
|
1316
|
+
var _start = toDateTime(editingAt);
|
|
1317
|
+
var editingDuration = Number((_request$durationMinu3 = request.durationMinutesByProductId) === null || _request$durationMinu3 === void 0 ? void 0 : _request$durationMinu3[String(product.id)]);
|
|
1318
|
+
if (!Number.isFinite(_start) || !Number.isInteger(editingDuration) || editingDuration <= 0) {
|
|
1319
|
+
throw availabilityError('INVALID_TARGET_FILTER', '编辑时间必须包含完整开始日期时间和明确的正整数时长');
|
|
1320
|
+
}
|
|
1321
|
+
// Editing restores the original interval, including its actual overnight
|
|
1322
|
+
// date. It neither adopts the current grid nor recomputes a flexible end.
|
|
1323
|
+
if (request.allowOutsideOperatingHoursForRequestedStartTimes || operatingRanges.some(function (range) {
|
|
1324
|
+
return range.start <= _start && _start < range.end;
|
|
1325
|
+
})) {
|
|
1326
|
+
addRange(_start, addMinutesZoned(_start, editingDuration, projection.meta.timezone));
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
// Explicit custom input keeps its existing start + requested duration
|
|
1331
|
+
// semantics. Remembered input above must never use this default-30 path.
|
|
1332
|
+
if (dateRange.startDate === dateRange.endDate) {
|
|
1333
|
+
resolveRequestedDurationStartTimes(product, request).forEach(function (startTime) {
|
|
1334
|
+
var sameDayStart = toDateTimeInDate(dateRange.startDate, startTime);
|
|
1335
|
+
var period = periods.find(function (item) {
|
|
1336
|
+
return item.businessDate === dateRange.startDate;
|
|
1337
|
+
});
|
|
1338
|
+
var periodRange = period ? normalizeAbsoluteRange(period) : null;
|
|
1339
|
+
var nextDayStart = addLocalCalendarDays(sameDayStart, 1);
|
|
1340
|
+
// HH:mm is entered within a selected business day, whose early hours
|
|
1341
|
+
// may belong to the next calendar day. Do not move other out-of-hours
|
|
1342
|
+
// manual input to tomorrow merely because the business closes overnight.
|
|
1343
|
+
var start = periodRange && !(periodRange.start <= sameDayStart && sameDayStart < periodRange.end) && periodRange.start <= nextDayStart && nextDayStart < periodRange.end ? nextDayStart : sameDayStart;
|
|
1344
|
+
if (request.allowOutsideOperatingHoursForRequestedStartTimes || operatingRanges.some(function (range) {
|
|
1345
|
+
return range.start <= start && start < range.end;
|
|
1346
|
+
})) {
|
|
1347
|
+
addRange(start, start + duration * 60000);
|
|
1348
|
+
}
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
1351
|
+
return _objectSpread(_objectSpread({
|
|
1352
|
+
productId: product.id,
|
|
1353
|
+
title: product.title,
|
|
1354
|
+
kind: product.kind,
|
|
1355
|
+
slotStepMinutes: step
|
|
1356
|
+
}, operatingEndAt ? {
|
|
1357
|
+
operatingEndAt: operatingEndAt
|
|
1358
|
+
} : {}), {}, {
|
|
1359
|
+
ranges: dedupeProductRanges(ranges)
|
|
1360
|
+
}, unavailableCurrentTime ? {
|
|
1361
|
+
unavailableCurrentTime: unavailableCurrentTime
|
|
1362
|
+
} : {});
|
|
1363
|
+
}
|
|
1111
1364
|
export function getProductTimeRanges(projection) {
|
|
1112
1365
|
var _extractFixedOffsetMi3, _request$productIds;
|
|
1113
1366
|
var request = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
@@ -1173,6 +1426,19 @@ export function getProductTimeRanges(projection) {
|
|
|
1173
1426
|
return current === null ? ranges : intersectRangeLists(current, ranges);
|
|
1174
1427
|
}, null) || [] : null;
|
|
1175
1428
|
var baseRanges = resourceRanges === null ? operatingRanges : intersectRangeLists(resourceRanges, operatingRanges);
|
|
1429
|
+
if (runtimeOptions.useDurationTimeGrid) {
|
|
1430
|
+
return getAlignedDurationRanges({
|
|
1431
|
+
projection: projection,
|
|
1432
|
+
product: product,
|
|
1433
|
+
request: request,
|
|
1434
|
+
runtimeOptions: runtimeOptions,
|
|
1435
|
+
dateRange: dateRange,
|
|
1436
|
+
operatingRanges: operatingRanges,
|
|
1437
|
+
baseRanges: baseRanges,
|
|
1438
|
+
resourceWindowIndex: resourceWindowIndex,
|
|
1439
|
+
fixedOffsetMinutes: fixedOffsetMinutes
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1176
1442
|
var durationMinutes = resolveRequestedDurationMinutes(product, request);
|
|
1177
1443
|
var flexibleStartAt = function () {
|
|
1178
1444
|
if (!product.isFlexibleDuration) return undefined;
|
|
@@ -1454,7 +1720,9 @@ function buildEvaluationContext(params) {
|
|
|
1454
1720
|
selectionsByGroupKey: selectionsByGroupKey,
|
|
1455
1721
|
useExactDurationCandidateMinute: params.useExactDurationCandidateMinute === true,
|
|
1456
1722
|
durationCandidateAnchorAtMs: Number.isFinite(durationCandidateAnchorAt) ? floorToMinute(durationCandidateAnchorAt) : null,
|
|
1457
|
-
allowExcludedScheduleDateOverride: params.allowExcludedScheduleDateOverride === true
|
|
1723
|
+
allowExcludedScheduleDateOverride: params.allowExcludedScheduleDateOverride === true,
|
|
1724
|
+
useDurationTimeGrid: params.useDurationTimeGrid === true,
|
|
1725
|
+
enforceSaleCutoff: params.enforceSaleCutoff === true
|
|
1458
1726
|
};
|
|
1459
1727
|
}
|
|
1460
1728
|
function summarizeStatuses(statuses) {
|
|
@@ -1504,7 +1772,7 @@ function summarizeStatusAggregate(aggregate) {
|
|
|
1504
1772
|
return 'unavailable';
|
|
1505
1773
|
}
|
|
1506
1774
|
function evaluateMatchedResourceSummary(params) {
|
|
1507
|
-
var
|
|
1775
|
+
var _ref8, _params$matchedCell$m;
|
|
1508
1776
|
var isPast = params.candidateRange.endMs <= params.evaluationContext.evaluatedAtMs;
|
|
1509
1777
|
if (!params.matchedCell) {
|
|
1510
1778
|
return {
|
|
@@ -1516,7 +1784,7 @@ function evaluateMatchedResourceSummary(params) {
|
|
|
1516
1784
|
};
|
|
1517
1785
|
}
|
|
1518
1786
|
var remainingCapacity = Math.max(0, params.matchedCell.remainingCapacity || 0);
|
|
1519
|
-
var maxCapacity = Math.max(0, (
|
|
1787
|
+
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
1788
|
var maxPartySize = isPast ? 0 : remainingCapacity;
|
|
1521
1789
|
var status = function () {
|
|
1522
1790
|
if (isPast) return 'past';
|
|
@@ -1942,6 +2210,8 @@ export function queryAvailabilityProjection(projection, request) {
|
|
|
1942
2210
|
projection: projection,
|
|
1943
2211
|
evaluatedAt: evaluatedAt,
|
|
1944
2212
|
resourceIds: request.resourceIds,
|
|
2213
|
+
useDurationTimeGrid: runtimeOptions.useDurationTimeGrid,
|
|
2214
|
+
enforceSaleCutoff: runtimeOptions.enforceSaleCutoff,
|
|
1945
2215
|
useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
|
|
1946
2216
|
allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
|
|
1947
2217
|
});
|
|
@@ -2032,6 +2302,8 @@ export function queryAvailabilityProjection(projection, request) {
|
|
|
2032
2302
|
partySize: normalizedPartySize
|
|
2033
2303
|
}, {
|
|
2034
2304
|
evaluatedAt: evaluatedAt,
|
|
2305
|
+
useDurationTimeGrid: runtimeOptions.useDurationTimeGrid,
|
|
2306
|
+
enforceSaleCutoff: runtimeOptions.enforceSaleCutoff,
|
|
2035
2307
|
useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
|
|
2036
2308
|
allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
|
|
2037
2309
|
});
|
|
@@ -2060,7 +2332,8 @@ export function queryAvailabilityProjection(projection, request) {
|
|
|
2060
2332
|
candidateRangeCache: candidateRangeCache,
|
|
2061
2333
|
evaluationContext: evaluationContext
|
|
2062
2334
|
});
|
|
2063
|
-
var
|
|
2335
|
+
var candidateDate = runtimeOptions.useDurationTimeGrid ? candidate.businessDate || candidate.date : candidate.date;
|
|
2336
|
+
var aggregate = byDate.get(candidateDate) || {
|
|
2064
2337
|
availableCount: 0,
|
|
2065
2338
|
totalCount: 0,
|
|
2066
2339
|
maxPartySize: 0,
|
|
@@ -2080,8 +2353,26 @@ export function queryAvailabilityProjection(projection, request) {
|
|
|
2080
2353
|
evaluated.reasonCodes.forEach(function (reasonCode) {
|
|
2081
2354
|
return aggregate.reasonCodeSet.add(reasonCode);
|
|
2082
2355
|
});
|
|
2083
|
-
byDate.set(
|
|
2356
|
+
byDate.set(candidateDate, aggregate);
|
|
2084
2357
|
});
|
|
2358
|
+
if (group.unavailableCurrentTime) {
|
|
2359
|
+
var current = group.unavailableCurrentTime;
|
|
2360
|
+
var aggregate = byDate.get(current.businessDate) || {
|
|
2361
|
+
availableCount: 0,
|
|
2362
|
+
totalCount: 0,
|
|
2363
|
+
maxPartySize: 0,
|
|
2364
|
+
remainingCapacity: 0,
|
|
2365
|
+
maxCapacity: 0,
|
|
2366
|
+
reasonCodeSet: new Set(),
|
|
2367
|
+
statusAggregate: createStatusAggregate()
|
|
2368
|
+
};
|
|
2369
|
+
aggregate.totalCount += 1;
|
|
2370
|
+
pushStatusAggregate(aggregate.statusAggregate, 'unavailable');
|
|
2371
|
+
current.reasonCodes.forEach(function (reason) {
|
|
2372
|
+
return aggregate.reasonCodeSet.add(reason);
|
|
2373
|
+
});
|
|
2374
|
+
byDate.set(current.businessDate, aggregate);
|
|
2375
|
+
}
|
|
2085
2376
|
var dates = enumerateDates(dateRange.startDate, dateRange.endDate).map(function (date) {
|
|
2086
2377
|
var aggregate = byDate.get(date);
|
|
2087
2378
|
return {
|
|
@@ -2143,10 +2434,22 @@ export function queryAvailabilityProjection(projection, request) {
|
|
|
2143
2434
|
evaluated.reasonCodes.forEach(function (reasonCode) {
|
|
2144
2435
|
return productReasonCodeSet.add(reasonCode);
|
|
2145
2436
|
});
|
|
2146
|
-
var
|
|
2437
|
+
var candidateDate = runtimeOptions.useDurationTimeGrid ? candidate.businessDate || candidate.date : candidate.date;
|
|
2438
|
+
var dateAggregate = dateStatusMap.get(candidateDate) || createStatusAggregate();
|
|
2147
2439
|
pushStatusAggregate(dateAggregate, evaluated.status);
|
|
2148
|
-
dateStatusMap.set(
|
|
2440
|
+
dateStatusMap.set(candidateDate, dateAggregate);
|
|
2149
2441
|
});
|
|
2442
|
+
if (group.unavailableCurrentTime) {
|
|
2443
|
+
var current = group.unavailableCurrentTime;
|
|
2444
|
+
totalTimeCount += 1;
|
|
2445
|
+
pushStatusAggregate(productStatusAggregate, 'unavailable');
|
|
2446
|
+
current.reasonCodes.forEach(function (reason) {
|
|
2447
|
+
return productReasonCodeSet.add(reason);
|
|
2448
|
+
});
|
|
2449
|
+
var dateAggregate = dateStatusMap.get(current.businessDate) || createStatusAggregate();
|
|
2450
|
+
pushStatusAggregate(dateAggregate, 'unavailable');
|
|
2451
|
+
dateStatusMap.set(current.businessDate, dateAggregate);
|
|
2452
|
+
}
|
|
2150
2453
|
var availableDateCount = Array.from(dateStatusMap.values()).filter(function (aggregate) {
|
|
2151
2454
|
var status = summarizeStatusAggregate(aggregate);
|
|
2152
2455
|
return status === 'available' || status === 'limited';
|
|
@@ -2233,6 +2536,8 @@ export function validateAvailabilitySelection(projection, params) {
|
|
|
2233
2536
|
projection: projection,
|
|
2234
2537
|
evaluatedAt: evaluatedAt,
|
|
2235
2538
|
requirementSelections: params.requirementSelections,
|
|
2539
|
+
useDurationTimeGrid: runtimeOptions.useDurationTimeGrid,
|
|
2540
|
+
enforceSaleCutoff: runtimeOptions.enforceSaleCutoff,
|
|
2236
2541
|
useExactDurationCandidateMinute: runtimeOptions.useExactDurationCandidateMinute,
|
|
2237
2542
|
allowExcludedScheduleDateOverride: runtimeOptions.allowExcludedScheduleDateOverride
|
|
2238
2543
|
})
|
|
@@ -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
|
|
@@ -328,7 +328,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
328
328
|
date: string;
|
|
329
329
|
status: string;
|
|
330
330
|
week: string;
|
|
331
|
-
weekNum: 0 | 2 | 1 |
|
|
331
|
+
weekNum: 0 | 2 | 1 | 6 | 4 | 5 | 3;
|
|
332
332
|
}[]>;
|
|
333
333
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
334
334
|
private getScheduleDataByIds;
|
|
@@ -141,7 +141,7 @@ function isMultiDayLike(cacheItem) {
|
|
|
141
141
|
* `_extend.resource / capacity / startDate / endDate` 等后续 booking mapper 需要的字段。
|
|
142
142
|
*/
|
|
143
143
|
export function prepareBookingCacheItem(cacheItem, ctx) {
|
|
144
|
-
if (isNormalBookingProduct(cacheItem) || hasPreparedBookingExtend(cacheItem)) {
|
|
144
|
+
if ((ctx === null || ctx === void 0 ? void 0 : ctx.rememberedTime) === undefined && (isNormalBookingProduct(cacheItem) || hasPreparedBookingExtend(cacheItem))) {
|
|
145
145
|
return cacheItem;
|
|
146
146
|
}
|
|
147
147
|
return getProductExtend({
|
|
@@ -99,6 +99,9 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
|
|
|
99
99
|
protected getSubModuleHooks(moduleName: string): any;
|
|
100
100
|
private createAvailabilityFacadeError;
|
|
101
101
|
private getAvailabilityScopeDescriptor;
|
|
102
|
+
private usesDurationTimeGrid;
|
|
103
|
+
private getCurrentAvailabilityBusinessDate;
|
|
104
|
+
private getAvailabilityBusinessDateRange;
|
|
102
105
|
private normalizeAvailabilityIdList;
|
|
103
106
|
private normalizeAvailabilityStringList;
|
|
104
107
|
private normalizeAvailabilityPrepareDescriptor;
|