@pisell/pisellos 2.3.98 → 2.3.100
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/model/strategy/adapter/promotion/index.js +0 -9
- package/dist/modules/ResourcePlanner/planner.d.ts +2 -2
- package/dist/modules/ResourcePlanner/planner.js +30 -2
- package/dist/modules/ResourcePlanner/types.d.ts +4 -0
- package/dist/solution/BaseSales/index.js +16 -15
- package/dist/solution/BookingByStep/index.d.ts +2 -2
- package/dist/solution/UnifiedBookingSales/index.d.ts +1 -1
- package/dist/solution/UnifiedBookingSales/index.js +8 -3
- package/lib/model/strategy/adapter/promotion/index.js +1 -46
- package/lib/modules/ResourcePlanner/planner.d.ts +2 -2
- package/lib/modules/ResourcePlanner/planner.js +28 -1
- package/lib/modules/ResourcePlanner/types.d.ts +4 -0
- package/lib/solution/BaseSales/index.js +3 -1
- package/lib/solution/BookingByStep/index.d.ts +2 -2
- package/lib/solution/UnifiedBookingSales/index.d.ts +1 -1
- package/lib/solution/UnifiedBookingSales/index.js +7 -2
- package/package.json +1 -1
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
// 导出评估器
|
|
2
|
-
export { PromotionEvaluator } from "./evaluator";
|
|
3
|
-
|
|
4
|
-
// 导出适配器
|
|
5
|
-
export { PromotionAdapter } from "./adapter";
|
|
6
|
-
export { default } from "./adapter";
|
|
7
|
-
|
|
8
|
-
// 导出策略配置示例常量
|
|
9
|
-
export { X_ITEMS_FOR_Y_PRICE_STRATEGY, BUY_X_GET_Y_FREE_STRATEGY, ITEM_REWARD_STRATEGY } from "./examples";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { AvailabilityProjection, AvailabilityProjectionInput, AvailabilityQuery, AvailabilityQueryResult, AvailabilitySelectionValidationParams, AvailabilitySelectionValidationResult, GetProductTimeRangesRequest, ProductTimeRangeGroup } from './types';
|
|
1
|
+
import type { AvailabilityProjection, AvailabilityProjectionInput, AvailabilityQuery, AvailabilityQueryResult, AvailabilitySelectionValidationParams, AvailabilitySelectionValidationResult, GetProductTimeRangesRequest, GetProductTimeRangesRuntimeOptions, ProductTimeRangeGroup } from './types';
|
|
2
2
|
export declare function createAvailabilityProjection(input: AvailabilityProjectionInput): AvailabilityProjection;
|
|
3
|
-
export declare function getProductTimeRanges(projection: AvailabilityProjection, request?: GetProductTimeRangesRequest): ProductTimeRangeGroup[];
|
|
3
|
+
export declare function getProductTimeRanges(projection: AvailabilityProjection, request?: GetProductTimeRangesRequest, runtimeOptions?: GetProductTimeRangesRuntimeOptions): ProductTimeRangeGroup[];
|
|
4
4
|
export declare function queryAvailabilityProjection(projection: AvailabilityProjection, request: AvailabilityQuery): AvailabilityQueryResult;
|
|
5
5
|
export declare function validateAvailabilitySelection(projection: AvailabilityProjection, params: AvailabilitySelectionValidationParams): AvailabilitySelectionValidationResult;
|
|
@@ -96,6 +96,9 @@ function addMinutesZoned(value, minutes, _timezoneName) {
|
|
|
96
96
|
function ceilToTenMinutes(value, _timezoneName) {
|
|
97
97
|
return ceilLocalScalarToTenMinutes(value);
|
|
98
98
|
}
|
|
99
|
+
function floorToMinute(value) {
|
|
100
|
+
return Math.floor(value / 60000) * 60000;
|
|
101
|
+
}
|
|
99
102
|
function nextDate(value, _timezoneName) {
|
|
100
103
|
return getNextLocalDate(value);
|
|
101
104
|
}
|
|
@@ -981,6 +984,9 @@ function dedupeProductRanges(ranges) {
|
|
|
981
984
|
}
|
|
982
985
|
function createDurationTimeRange(product, start, durationMinutes, projection, fixedOffsetMinutes) {
|
|
983
986
|
var bookingEnd = addMinutesZoned(start, durationMinutes, projection.meta.timezone);
|
|
987
|
+
return createDurationTimeRangeWithEnd(product, start, bookingEnd, projection, fixedOffsetMinutes);
|
|
988
|
+
}
|
|
989
|
+
function createDurationTimeRangeWithEnd(product, start, bookingEnd, projection, fixedOffsetMinutes) {
|
|
984
990
|
return {
|
|
985
991
|
key: "".concat(String(product.id), ":").concat(start, ":").concat(bookingEnd),
|
|
986
992
|
productId: product.id,
|
|
@@ -999,6 +1005,7 @@ function createDurationTimeRange(product, start, durationMinutes, projection, fi
|
|
|
999
1005
|
export function getProductTimeRanges(projection) {
|
|
1000
1006
|
var _extractFixedOffsetMi3, _request$productIds;
|
|
1001
1007
|
var request = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
1008
|
+
var runtimeOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
1002
1009
|
var normalizedPartySize = normalizePartySize(request.partySize);
|
|
1003
1010
|
var dateRange = resolveProjectionDateRange(projection, request.dateRange);
|
|
1004
1011
|
var slotStepMinutes = projection.meta.defaults.slotStepMinutes;
|
|
@@ -1045,10 +1052,29 @@ export function getProductTimeRanges(projection) {
|
|
|
1045
1052
|
}, null) || [] : null;
|
|
1046
1053
|
var baseRanges = resourceRanges === null ? operatingRanges : intersectRangeLists(resourceRanges, operatingRanges);
|
|
1047
1054
|
var durationMinutes = resolveRequestedDurationMinutes(product, request);
|
|
1055
|
+
var flexibleStartAt = function () {
|
|
1056
|
+
if (!product.isFlexibleDuration) return undefined;
|
|
1057
|
+
var evaluatedAt = toDateTime(runtimeOptions.evaluatedAt || projection.meta.durationCandidateAnchorAt, projection.meta.timezone);
|
|
1058
|
+
if (!Number.isFinite(evaluatedAt)) {
|
|
1059
|
+
throw availabilityError('INVALID_TARGET_FILTER', 'runtimeOptions.evaluatedAt 必须是有效时间', {
|
|
1060
|
+
evaluatedAt: runtimeOptions.evaluatedAt
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
1063
|
+
return floorToMinute(evaluatedAt);
|
|
1064
|
+
}();
|
|
1048
1065
|
var durationAnchor = ceilToTenMinutes(toDateTime(projection.meta.durationCandidateAnchorAt, projection.meta.timezone), projection.meta.timezone);
|
|
1049
1066
|
var requestedStartTimes = resolveRequestedDurationStartTimes(product, request);
|
|
1050
1067
|
var ranges = [];
|
|
1051
1068
|
baseRanges.forEach(function (range) {
|
|
1069
|
+
if (product.isFlexibleDuration && flexibleStartAt !== undefined) {
|
|
1070
|
+
var start = Math.max(range.start, flexibleStartAt);
|
|
1071
|
+
if (start >= range.end) return;
|
|
1072
|
+
var bookingDate = formatDate(start);
|
|
1073
|
+
if (bookingDate >= dateRange.startDate && bookingDate <= dateRange.endDate) {
|
|
1074
|
+
ranges.push(createDurationTimeRangeWithEnd(product, start, range.end, projection, fixedOffsetMinutes));
|
|
1075
|
+
}
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1052
1078
|
if (range.end <= durationAnchor) return;
|
|
1053
1079
|
var cursor = range.start;
|
|
1054
1080
|
if (cursor < durationAnchor) {
|
|
@@ -1057,8 +1083,8 @@ export function getProductTimeRanges(projection) {
|
|
|
1057
1083
|
while (true) {
|
|
1058
1084
|
var bookingEnd = addMinutesZoned(cursor, durationMinutes, projection.meta.timezone);
|
|
1059
1085
|
if (bookingEnd > range.end) break;
|
|
1060
|
-
var
|
|
1061
|
-
if (
|
|
1086
|
+
var _bookingDate = formatDate(cursor);
|
|
1087
|
+
if (_bookingDate >= dateRange.startDate && _bookingDate <= dateRange.endDate) {
|
|
1062
1088
|
ranges.push(createDurationTimeRange(product, cursor, durationMinutes, projection, fixedOffsetMinutes));
|
|
1063
1089
|
}
|
|
1064
1090
|
cursor = addMinutesZoned(cursor, slotStepMinutes, projection.meta.timezone);
|
|
@@ -1858,6 +1884,8 @@ export function queryAvailabilityProjection(projection, request) {
|
|
|
1858
1884
|
dateRange: dateRange,
|
|
1859
1885
|
resourceIds: request.resourceIds,
|
|
1860
1886
|
partySize: normalizedPartySize
|
|
1887
|
+
}, {
|
|
1888
|
+
evaluatedAt: evaluatedAt
|
|
1861
1889
|
});
|
|
1862
1890
|
var candidateGroupMap = new Map(candidateGroups.map(function (group) {
|
|
1863
1891
|
return [String(group.productId), group];
|
|
@@ -81,6 +81,7 @@ export interface AvailabilityProduct {
|
|
|
81
81
|
id: AvailabilityId;
|
|
82
82
|
title?: string;
|
|
83
83
|
kind: AvailabilityProductKind;
|
|
84
|
+
isFlexibleDuration?: boolean;
|
|
84
85
|
durationMinutes?: number;
|
|
85
86
|
quantity?: number;
|
|
86
87
|
capacityRequired?: number;
|
|
@@ -240,6 +241,9 @@ export interface GetProductTimeRangesRequest {
|
|
|
240
241
|
*/
|
|
241
242
|
allowOutsideOperatingHoursForRequestedStartTimes?: boolean;
|
|
242
243
|
}
|
|
244
|
+
export interface GetProductTimeRangesRuntimeOptions {
|
|
245
|
+
evaluatedAt?: string;
|
|
246
|
+
}
|
|
243
247
|
export interface QueryAvailabilityBaseRequest {
|
|
244
248
|
productIds?: AvailabilityId[];
|
|
245
249
|
resourceIds?: AvailabilityId[];
|
|
@@ -2410,7 +2410,7 @@ export var BaseSalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2410
2410
|
key: "restoreOrder",
|
|
2411
2411
|
value: function () {
|
|
2412
2412
|
var _restoreOrder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee21() {
|
|
2413
|
-
var _this$store$payment, tempOrder, wallet;
|
|
2413
|
+
var _this$store$payment, tempOrder, appDataChanged, wallet;
|
|
2414
2414
|
return _regeneratorRuntime().wrap(function _callee21$(_context21) {
|
|
2415
2415
|
while (1) switch (_context21.prev = _context21.next) {
|
|
2416
2416
|
case 0:
|
|
@@ -2422,43 +2422,44 @@ export var BaseSalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2422
2422
|
throw new Error('scanOrder 解决方案需要 order 模块支持');
|
|
2423
2423
|
case 3:
|
|
2424
2424
|
// this.store.resource = null;
|
|
2425
|
-
tempOrder = this.store.order.restoreOrder();
|
|
2425
|
+
tempOrder = this.store.order.restoreOrder(); // 先补齐店铺级订单字段,再通知监听方,避免发布带空税区/币种的中间快照。
|
|
2426
|
+
appDataChanged = this.syncAppDataToTempOrder(tempOrder);
|
|
2426
2427
|
this.currentSalesDetail = null;
|
|
2427
2428
|
this.discountConfigCacheKey = null;
|
|
2428
2429
|
this.hasManualDiscountSelection = false;
|
|
2429
2430
|
wallet = (_this$store$payment = this.store.payment) === null || _this$store$payment === void 0 ? void 0 : _this$store$payment.wallet;
|
|
2430
2431
|
if (!wallet) {
|
|
2431
|
-
_context21.next =
|
|
2432
|
+
_context21.next = 14;
|
|
2432
2433
|
break;
|
|
2433
2434
|
}
|
|
2434
2435
|
this.walletAssetsRefreshSequence += 1;
|
|
2435
2436
|
wallet.clearAllCache();
|
|
2436
|
-
_context21.next =
|
|
2437
|
+
_context21.next = 14;
|
|
2437
2438
|
return this.publishWalletAssetsState(wallet.getWalletAssetsState());
|
|
2438
|
-
case
|
|
2439
|
-
_context21.next =
|
|
2439
|
+
case 14:
|
|
2440
|
+
_context21.next = 16;
|
|
2440
2441
|
return this.effectsEmit('onTempOrderReplaced', {
|
|
2441
2442
|
tempOrder: tempOrder
|
|
2442
2443
|
});
|
|
2443
|
-
case
|
|
2444
|
-
if (!(
|
|
2445
|
-
_context21.next =
|
|
2444
|
+
case 16:
|
|
2445
|
+
if (!(appDataChanged && this.isTempOrderPersistEnabled())) {
|
|
2446
|
+
_context21.next = 20;
|
|
2446
2447
|
break;
|
|
2447
2448
|
}
|
|
2448
2449
|
this.store.order.persistTempOrder();
|
|
2449
|
-
_context21.next =
|
|
2450
|
+
_context21.next = 20;
|
|
2450
2451
|
return this.store.order.saveDraft();
|
|
2451
|
-
case
|
|
2452
|
+
case 20:
|
|
2452
2453
|
return _context21.abrupt("return", tempOrder);
|
|
2453
|
-
case
|
|
2454
|
-
_context21.prev =
|
|
2454
|
+
case 23:
|
|
2455
|
+
_context21.prev = 23;
|
|
2455
2456
|
_context21.t0 = _context21["catch"](0);
|
|
2456
2457
|
throw _context21.t0;
|
|
2457
|
-
case
|
|
2458
|
+
case 26:
|
|
2458
2459
|
case "end":
|
|
2459
2460
|
return _context21.stop();
|
|
2460
2461
|
}
|
|
2461
|
-
}, _callee21, this, [[0,
|
|
2462
|
+
}, _callee21, this, [[0, 23]]);
|
|
2462
2463
|
}));
|
|
2463
2464
|
function restoreOrder() {
|
|
2464
2465
|
return _restoreOrder.apply(this, arguments);
|
|
@@ -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 |
|
|
329
|
+
weekNum: 0 | 5 | 3 | 1 | 2 | 4 | 6;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -345,7 +345,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
345
345
|
count: number;
|
|
346
346
|
left: number;
|
|
347
347
|
summaryCount: number;
|
|
348
|
-
status: "
|
|
348
|
+
status: "sold_out" | "lots_of_space" | "filling_up_fast";
|
|
349
349
|
}[];
|
|
350
350
|
/**
|
|
351
351
|
* 找到多个资源的公共可用时间段
|
|
@@ -244,7 +244,7 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
|
|
|
244
244
|
private releaseAvailabilityCommitLock;
|
|
245
245
|
/** IO boundary: loads catalog, schedules, resources, occupancies, and registers one context. */
|
|
246
246
|
prepareAvailabilityProjection(params: UnifiedBookingSalesPrepareAvailabilityProjectionParams): Promise<AvailabilityContextRef>;
|
|
247
|
-
/**
|
|
247
|
+
/** Candidate calculation over the current context projection and runtime minute. */
|
|
248
248
|
getProductTimeRanges(contextId: string, request?: GetProductTimeRangesRequest): Promise<ContextualProductTimeRangeGroup[]>;
|
|
249
249
|
/** Thin facade: auto-refresh on cart drift, then delegate to the pure projection query. */
|
|
250
250
|
queryBookingAvailability(contextId: string, request: ContextualAvailabilityQuery): Promise<ContextualAvailabilityQueryResult>;
|
|
@@ -36,6 +36,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" ==
|
|
|
36
36
|
import dayjs from 'dayjs';
|
|
37
37
|
import { cloneDeep } from 'lodash-es';
|
|
38
38
|
import { OpenDataModule } from "../../modules";
|
|
39
|
+
import { isProductFlexibleDuration } from "../../modules/BookingContext/utils";
|
|
39
40
|
import { getScheduleStartEndTimePoints } from "../../modules/Schedule/getDateIsInSchedule";
|
|
40
41
|
import { AvailabilityError, createAvailabilityProjection, getProductTimeRanges as getProjectionProductTimeRanges, queryAvailabilityProjection, validateAvailabilitySelection } from "../../modules/ResourcePlanner";
|
|
41
42
|
import { UnifiedBookingSalesHooks } from "./types";
|
|
@@ -544,6 +545,7 @@ export function normalizeProductForAvailability(product) {
|
|
|
544
545
|
var fixedOffsetMinutes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : captureRuntimeOffsetMinutes();
|
|
545
546
|
var raw = product;
|
|
546
547
|
var kind = resolveProductKind(raw);
|
|
548
|
+
var isFlexibleDuration = kind === 'duration' && isProductFlexibleDuration(raw.duration);
|
|
547
549
|
var sessionRules = [];
|
|
548
550
|
var sessionRanges = [];
|
|
549
551
|
var explicitSession = ((_raw$cartDetailValue = raw.cartDetailValue) === null || _raw$cartDetailValue === void 0 ? void 0 : _raw$cartDetailValue.session) || ((_raw$_extend = raw._extend) === null || _raw$_extend === void 0 || (_raw$_extend = _raw$_extend.other) === null || _raw$_extend === void 0 ? void 0 : _raw$_extend.session) || raw.session;
|
|
@@ -565,7 +567,8 @@ export function normalizeProductForAvailability(product) {
|
|
|
565
567
|
id: (_raw$id = raw.id) !== null && _raw$id !== void 0 ? _raw$id : raw.product_id,
|
|
566
568
|
title: pickLocalizedText(raw.title || raw.name || raw.product_title),
|
|
567
569
|
kind: kind,
|
|
568
|
-
|
|
570
|
+
isFlexibleDuration: isFlexibleDuration || undefined,
|
|
571
|
+
durationMinutes: kind === 'duration' && !isFlexibleDuration ? Math.max(1, Number(((_raw$duration = raw.duration) === null || _raw$duration === void 0 ? void 0 : _raw$duration.value) || raw.duration || raw.service_duration || 30) || 30) : undefined,
|
|
569
572
|
requirementGroups: normalizeRequirementGroups(raw),
|
|
570
573
|
sessionRules: sessionRules,
|
|
571
574
|
sessionRanges: sessionRanges,
|
|
@@ -4457,7 +4460,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4457
4460
|
return _prepareAvailabilityProjection.apply(this, arguments);
|
|
4458
4461
|
}
|
|
4459
4462
|
return prepareAvailabilityProjection;
|
|
4460
|
-
}() /**
|
|
4463
|
+
}() /** Candidate calculation over the current context projection and runtime minute. */)
|
|
4461
4464
|
}, {
|
|
4462
4465
|
key: "getProductTimeRanges",
|
|
4463
4466
|
value: (function () {
|
|
@@ -4488,7 +4491,9 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4488
4491
|
});
|
|
4489
4492
|
return _context40.abrupt("return", getProjectionProductTimeRanges(projectionEntry.projection, _objectSpread(_objectSpread({}, request), allowOutsideOperatingHoursForRequestedStartTimes ? {
|
|
4490
4493
|
allowOutsideOperatingHoursForRequestedStartTimes: true
|
|
4491
|
-
} : {})
|
|
4494
|
+
} : {}), {
|
|
4495
|
+
evaluatedAt: this.getAvailabilityRuntimeDateTime()
|
|
4496
|
+
}).map(function (group) {
|
|
4492
4497
|
return _objectSpread(_objectSpread({}, group), {}, {
|
|
4493
4498
|
ranges: group.ranges.map(function (candidate) {
|
|
4494
4499
|
return _this10.decorateAvailabilityCandidate(context.contextId, contextVersion, candidate);
|
|
@@ -1,46 +1 @@
|
|
|
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; }
|
|
1
|
+
"use strict";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { AvailabilityProjection, AvailabilityProjectionInput, AvailabilityQuery, AvailabilityQueryResult, AvailabilitySelectionValidationParams, AvailabilitySelectionValidationResult, GetProductTimeRangesRequest, ProductTimeRangeGroup } from './types';
|
|
1
|
+
import type { AvailabilityProjection, AvailabilityProjectionInput, AvailabilityQuery, AvailabilityQueryResult, AvailabilitySelectionValidationParams, AvailabilitySelectionValidationResult, GetProductTimeRangesRequest, GetProductTimeRangesRuntimeOptions, ProductTimeRangeGroup } from './types';
|
|
2
2
|
export declare function createAvailabilityProjection(input: AvailabilityProjectionInput): AvailabilityProjection;
|
|
3
|
-
export declare function getProductTimeRanges(projection: AvailabilityProjection, request?: GetProductTimeRangesRequest): ProductTimeRangeGroup[];
|
|
3
|
+
export declare function getProductTimeRanges(projection: AvailabilityProjection, request?: GetProductTimeRangesRequest, runtimeOptions?: GetProductTimeRangesRuntimeOptions): ProductTimeRangeGroup[];
|
|
4
4
|
export declare function queryAvailabilityProjection(projection: AvailabilityProjection, request: AvailabilityQuery): AvailabilityQueryResult;
|
|
5
5
|
export declare function validateAvailabilitySelection(projection: AvailabilityProjection, params: AvailabilitySelectionValidationParams): AvailabilitySelectionValidationResult;
|
|
@@ -88,6 +88,9 @@ function addMinutesZoned(value, minutes, _timezoneName) {
|
|
|
88
88
|
function ceilToTenMinutes(value, _timezoneName) {
|
|
89
89
|
return (0, _localClock.ceilLocalScalarToTenMinutes)(value);
|
|
90
90
|
}
|
|
91
|
+
function floorToMinute(value) {
|
|
92
|
+
return Math.floor(value / 60000) * 60000;
|
|
93
|
+
}
|
|
91
94
|
function nextDate(value, _timezoneName) {
|
|
92
95
|
return (0, _localClock.nextDate)(value);
|
|
93
96
|
}
|
|
@@ -880,6 +883,9 @@ function dedupeProductRanges(ranges) {
|
|
|
880
883
|
}
|
|
881
884
|
function createDurationTimeRange(product, start, durationMinutes, projection, fixedOffsetMinutes) {
|
|
882
885
|
const bookingEnd = addMinutesZoned(start, durationMinutes, projection.meta.timezone);
|
|
886
|
+
return createDurationTimeRangeWithEnd(product, start, bookingEnd, projection, fixedOffsetMinutes);
|
|
887
|
+
}
|
|
888
|
+
function createDurationTimeRangeWithEnd(product, start, bookingEnd, projection, fixedOffsetMinutes) {
|
|
883
889
|
return {
|
|
884
890
|
key: `${String(product.id)}:${start}:${bookingEnd}`,
|
|
885
891
|
productId: product.id,
|
|
@@ -895,7 +901,7 @@ function createDurationTimeRange(product, start, durationMinutes, projection, fi
|
|
|
895
901
|
scheduleRefs: []
|
|
896
902
|
};
|
|
897
903
|
}
|
|
898
|
-
function getProductTimeRanges(projection, request = {}) {
|
|
904
|
+
function getProductTimeRanges(projection, request = {}, runtimeOptions = {}) {
|
|
899
905
|
const normalizedPartySize = normalizePartySize(request.partySize);
|
|
900
906
|
const dateRange = resolveProjectionDateRange(projection, request.dateRange);
|
|
901
907
|
const slotStepMinutes = projection.meta.defaults.slotStepMinutes;
|
|
@@ -934,10 +940,29 @@ function getProductTimeRanges(projection, request = {}) {
|
|
|
934
940
|
})).reduce((current, ranges) => current === null ? ranges : intersectRangeLists(current, ranges), null) || [] : null;
|
|
935
941
|
const baseRanges = resourceRanges === null ? operatingRanges : intersectRangeLists(resourceRanges, operatingRanges);
|
|
936
942
|
const durationMinutes = resolveRequestedDurationMinutes(product, request);
|
|
943
|
+
const flexibleStartAt = (() => {
|
|
944
|
+
if (!product.isFlexibleDuration) return undefined;
|
|
945
|
+
const evaluatedAt = toDateTime(runtimeOptions.evaluatedAt || projection.meta.durationCandidateAnchorAt, projection.meta.timezone);
|
|
946
|
+
if (!Number.isFinite(evaluatedAt)) {
|
|
947
|
+
throw availabilityError('INVALID_TARGET_FILTER', 'runtimeOptions.evaluatedAt 必须是有效时间', {
|
|
948
|
+
evaluatedAt: runtimeOptions.evaluatedAt
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
return floorToMinute(evaluatedAt);
|
|
952
|
+
})();
|
|
937
953
|
const durationAnchor = ceilToTenMinutes(toDateTime(projection.meta.durationCandidateAnchorAt, projection.meta.timezone), projection.meta.timezone);
|
|
938
954
|
const requestedStartTimes = resolveRequestedDurationStartTimes(product, request);
|
|
939
955
|
const ranges = [];
|
|
940
956
|
baseRanges.forEach(range => {
|
|
957
|
+
if (product.isFlexibleDuration && flexibleStartAt !== undefined) {
|
|
958
|
+
const start = Math.max(range.start, flexibleStartAt);
|
|
959
|
+
if (start >= range.end) return;
|
|
960
|
+
const bookingDate = formatDate(start);
|
|
961
|
+
if (bookingDate >= dateRange.startDate && bookingDate <= dateRange.endDate) {
|
|
962
|
+
ranges.push(createDurationTimeRangeWithEnd(product, start, range.end, projection, fixedOffsetMinutes));
|
|
963
|
+
}
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
941
966
|
if (range.end <= durationAnchor) return;
|
|
942
967
|
let cursor = range.start;
|
|
943
968
|
if (cursor < durationAnchor) {
|
|
@@ -1593,6 +1618,8 @@ function queryAvailabilityProjection(projection, request) {
|
|
|
1593
1618
|
dateRange,
|
|
1594
1619
|
resourceIds: request.resourceIds,
|
|
1595
1620
|
partySize: normalizedPartySize
|
|
1621
|
+
}, {
|
|
1622
|
+
evaluatedAt
|
|
1596
1623
|
});
|
|
1597
1624
|
const candidateGroupMap = new Map(candidateGroups.map(group => [String(group.productId), group]));
|
|
1598
1625
|
if (request.target === 'date') {
|
|
@@ -81,6 +81,7 @@ export interface AvailabilityProduct {
|
|
|
81
81
|
id: AvailabilityId;
|
|
82
82
|
title?: string;
|
|
83
83
|
kind: AvailabilityProductKind;
|
|
84
|
+
isFlexibleDuration?: boolean;
|
|
84
85
|
durationMinutes?: number;
|
|
85
86
|
quantity?: number;
|
|
86
87
|
capacityRequired?: number;
|
|
@@ -240,6 +241,9 @@ export interface GetProductTimeRangesRequest {
|
|
|
240
241
|
*/
|
|
241
242
|
allowOutsideOperatingHoursForRequestedStartTimes?: boolean;
|
|
242
243
|
}
|
|
244
|
+
export interface GetProductTimeRangesRuntimeOptions {
|
|
245
|
+
evaluatedAt?: string;
|
|
246
|
+
}
|
|
243
247
|
export interface QueryAvailabilityBaseRequest {
|
|
244
248
|
productIds?: AvailabilityId[];
|
|
245
249
|
resourceIds?: AvailabilityId[];
|
|
@@ -1600,6 +1600,8 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1600
1600
|
}
|
|
1601
1601
|
// this.store.resource = null;
|
|
1602
1602
|
const tempOrder = this.store.order.restoreOrder();
|
|
1603
|
+
// 先补齐店铺级订单字段,再通知监听方,避免发布带空税区/币种的中间快照。
|
|
1604
|
+
const appDataChanged = this.syncAppDataToTempOrder(tempOrder);
|
|
1603
1605
|
this.currentSalesDetail = null;
|
|
1604
1606
|
this.discountConfigCacheKey = null;
|
|
1605
1607
|
this.hasManualDiscountSelection = false;
|
|
@@ -1612,7 +1614,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1612
1614
|
await this.effectsEmit('onTempOrderReplaced', {
|
|
1613
1615
|
tempOrder
|
|
1614
1616
|
});
|
|
1615
|
-
if (
|
|
1617
|
+
if (appDataChanged && this.isTempOrderPersistEnabled()) {
|
|
1616
1618
|
this.store.order.persistTempOrder();
|
|
1617
1619
|
await this.store.order.saveDraft();
|
|
1618
1620
|
}
|
|
@@ -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 |
|
|
329
|
+
weekNum: 0 | 5 | 3 | 1 | 2 | 4 | 6;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -345,7 +345,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
345
345
|
count: number;
|
|
346
346
|
left: number;
|
|
347
347
|
summaryCount: number;
|
|
348
|
-
status: "
|
|
348
|
+
status: "sold_out" | "lots_of_space" | "filling_up_fast";
|
|
349
349
|
}[];
|
|
350
350
|
/**
|
|
351
351
|
* 找到多个资源的公共可用时间段
|
|
@@ -244,7 +244,7 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
|
|
|
244
244
|
private releaseAvailabilityCommitLock;
|
|
245
245
|
/** IO boundary: loads catalog, schedules, resources, occupancies, and registers one context. */
|
|
246
246
|
prepareAvailabilityProjection(params: UnifiedBookingSalesPrepareAvailabilityProjectionParams): Promise<AvailabilityContextRef>;
|
|
247
|
-
/**
|
|
247
|
+
/** Candidate calculation over the current context projection and runtime minute. */
|
|
248
248
|
getProductTimeRanges(contextId: string, request?: GetProductTimeRangesRequest): Promise<ContextualProductTimeRangeGroup[]>;
|
|
249
249
|
/** Thin facade: auto-refresh on cart drift, then delegate to the pure projection query. */
|
|
250
250
|
queryBookingAvailability(contextId: string, request: ContextualAvailabilityQuery): Promise<ContextualAvailabilityQueryResult>;
|
|
@@ -32,6 +32,7 @@ exports.normalizeProductForAvailability = normalizeProductForAvailability;
|
|
|
32
32
|
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
33
33
|
var _lodashEs = require("lodash-es");
|
|
34
34
|
var _modules = require("../../modules");
|
|
35
|
+
var _utils = require("../../modules/BookingContext/utils");
|
|
35
36
|
var _getDateIsInSchedule = require("../../modules/Schedule/getDateIsInSchedule");
|
|
36
37
|
var _ResourcePlanner = require("../../modules/ResourcePlanner");
|
|
37
38
|
var _types = require("./types");
|
|
@@ -503,6 +504,7 @@ function resolveProductScheduleItems(product, scheduleList) {
|
|
|
503
504
|
function normalizeProductForAvailability(product, scheduleList = [], fixedOffsetMinutes = (0, _localClock.captureRuntimeOffsetMinutes)()) {
|
|
504
505
|
const raw = product;
|
|
505
506
|
const kind = resolveProductKind(raw);
|
|
507
|
+
const isFlexibleDuration = kind === 'duration' && (0, _utils.isProductFlexibleDuration)(raw.duration);
|
|
506
508
|
const sessionRules = [];
|
|
507
509
|
const sessionRanges = [];
|
|
508
510
|
const explicitSession = raw.cartDetailValue?.session || raw._extend?.other?.session || raw.session;
|
|
@@ -524,7 +526,8 @@ function normalizeProductForAvailability(product, scheduleList = [], fixedOffset
|
|
|
524
526
|
id: raw.id ?? raw.product_id,
|
|
525
527
|
title: pickLocalizedText(raw.title || raw.name || raw.product_title),
|
|
526
528
|
kind,
|
|
527
|
-
|
|
529
|
+
isFlexibleDuration: isFlexibleDuration || undefined,
|
|
530
|
+
durationMinutes: kind === 'duration' && !isFlexibleDuration ? Math.max(1, Number(raw.duration?.value || raw.duration || raw.service_duration || 30) || 30) : undefined,
|
|
528
531
|
requirementGroups: normalizeRequirementGroups(raw),
|
|
529
532
|
sessionRules,
|
|
530
533
|
sessionRanges,
|
|
@@ -2919,7 +2922,7 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
|
|
|
2919
2922
|
return handle;
|
|
2920
2923
|
}
|
|
2921
2924
|
|
|
2922
|
-
/**
|
|
2925
|
+
/** Candidate calculation over the current context projection and runtime minute. */
|
|
2923
2926
|
async getProductTimeRanges(contextId, request = {}) {
|
|
2924
2927
|
const {
|
|
2925
2928
|
context,
|
|
@@ -2932,6 +2935,8 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
|
|
|
2932
2935
|
...(allowOutsideOperatingHoursForRequestedStartTimes ? {
|
|
2933
2936
|
allowOutsideOperatingHoursForRequestedStartTimes: true
|
|
2934
2937
|
} : {})
|
|
2938
|
+
}, {
|
|
2939
|
+
evaluatedAt: this.getAvailabilityRuntimeDateTime()
|
|
2935
2940
|
}).map(group => ({
|
|
2936
2941
|
...group,
|
|
2937
2942
|
ranges: group.ranges.map(candidate => this.decorateAvailabilityCandidate(context.contextId, contextVersion, candidate))
|