@pisell/pisellos 0.10.26 → 0.10.28
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/Order/index.d.ts +1 -1
- package/dist/modules/Payment/walletpass.js +20 -21
- package/dist/modules/ResourcePlanner/planner.js +21 -2
- package/dist/modules/ResourcePlanner/types.d.ts +7 -0
- package/dist/modules/Rules/index.js +1 -1
- package/dist/solution/BookingByStep/index.d.ts +2 -2
- package/dist/solution/BookingTicket/index.d.ts +13 -1
- package/dist/solution/UnifiedBookingSales/index.js +14 -8
- package/lib/modules/Order/index.d.ts +1 -1
- package/lib/modules/Payment/walletpass.js +14 -11
- package/lib/modules/ResourcePlanner/planner.js +20 -3
- package/lib/modules/ResourcePlanner/types.d.ts +7 -0
- package/lib/modules/Rules/index.js +1 -1
- package/lib/solution/BookingByStep/index.d.ts +2 -2
- package/lib/solution/BookingTicket/index.d.ts +13 -1
- package/lib/solution/UnifiedBookingSales/index.js +10 -4
- package/package.json +1 -1
|
@@ -533,7 +533,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
533
533
|
generateIdempotencyToken(): string;
|
|
534
534
|
syncPaymentsToOrder<T = any>(params: SyncPaymentsToOrderParams): Promise<SyncPaymentsToOrderResult<T>>;
|
|
535
535
|
createOrder(params: CommitOrderParams['query']): {
|
|
536
|
-
type: "
|
|
536
|
+
type: "appointment_booking" | "virtual";
|
|
537
537
|
platform: string;
|
|
538
538
|
sales_channel: string;
|
|
539
539
|
order_sales_channel: string;
|
|
@@ -851,7 +851,7 @@ export var WalletPassPaymentImpl = /*#__PURE__*/function () {
|
|
|
851
851
|
key: "getUserIdentificationCodeListAsync",
|
|
852
852
|
value: function () {
|
|
853
853
|
var _getUserIdentificationCodeListAsync = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6(params) {
|
|
854
|
-
var _newParams$products, _newParams$prepare_pa, _this$walletParams4, newParams,
|
|
854
|
+
var _newParams$products, _newParams$prepare_pa, _this$walletParams4, newParams, response, sortedData;
|
|
855
855
|
return _regeneratorRuntime().wrap(function _callee6$(_context6) {
|
|
856
856
|
while (1) switch (_context6.prev = _context6.next) {
|
|
857
857
|
case 0:
|
|
@@ -864,20 +864,19 @@ export var WalletPassPaymentImpl = /*#__PURE__*/function () {
|
|
|
864
864
|
this.paymentModule.logInfo('[WalletPass] 商品列表为空,跳过获取用户识别码列表');
|
|
865
865
|
return _context6.abrupt("return", []);
|
|
866
866
|
case 5:
|
|
867
|
-
platform = this.paymentModule.getPlatform();
|
|
868
|
-
if (
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
this.
|
|
874
|
-
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
case 11:
|
|
867
|
+
// const platform = this.paymentModule.getPlatform();
|
|
868
|
+
// if (platform === 'pc' || platform === 'h5') {
|
|
869
|
+
// this.userIdentificationCodes = [];
|
|
870
|
+
// this.emitEvent(WalletPassHooks.OnUserIdentificationCodesUpdated, {
|
|
871
|
+
// userIdentificationCodes: [],
|
|
872
|
+
// } as OnUserIdentificationCodesUpdatedEventData);
|
|
873
|
+
// this.paymentModule.logInfo(
|
|
874
|
+
// '[WalletPass] 用户端平台跳过获取用户识别码列表',
|
|
875
|
+
// { platform },
|
|
876
|
+
// );
|
|
877
|
+
// return [];
|
|
878
|
+
// }
|
|
879
|
+
|
|
881
880
|
if (typeof newParams.payment_order_id === 'string' && newParams.payment_order_id.startsWith('LOCAL_')) {
|
|
882
881
|
newParams.payment_order_id = undefined;
|
|
883
882
|
}
|
|
@@ -888,9 +887,9 @@ export var WalletPassPaymentImpl = /*#__PURE__*/function () {
|
|
|
888
887
|
filter_prepare_wallet_pass: newParams.filter_prepare_wallet_pass,
|
|
889
888
|
payment_order_id: (_this$walletParams4 = this.walletParams) === null || _this$walletParams4 === void 0 ? void 0 : _this$walletParams4.payment_order_id
|
|
890
889
|
});
|
|
891
|
-
_context6.next =
|
|
890
|
+
_context6.next = 9;
|
|
892
891
|
return this.paymentModule.request.post('/machinecode/prepare/deduction', newParams);
|
|
893
|
-
case
|
|
892
|
+
case 9:
|
|
894
893
|
response = _context6.sent;
|
|
895
894
|
// 对获取到的数据进行排序,将错误码为 500100、500200、500300 的项目排到最后
|
|
896
895
|
sortedData = sortUserIdentificationCodeList((response === null || response === void 0 ? void 0 : response.data) || []);
|
|
@@ -911,19 +910,19 @@ export var WalletPassPaymentImpl = /*#__PURE__*/function () {
|
|
|
911
910
|
})
|
|
912
911
|
});
|
|
913
912
|
return _context6.abrupt("return", this.userIdentificationCodes);
|
|
914
|
-
case
|
|
915
|
-
_context6.prev =
|
|
913
|
+
case 17:
|
|
914
|
+
_context6.prev = 17;
|
|
916
915
|
_context6.t0 = _context6["catch"](0);
|
|
917
916
|
this.paymentModule.logError('[WalletPass] 获取用户识别码列表失败', _context6.t0, {
|
|
918
917
|
customer_id: params.customer_id,
|
|
919
918
|
available: params.available
|
|
920
919
|
});
|
|
921
920
|
return _context6.abrupt("return", []);
|
|
922
|
-
case
|
|
921
|
+
case 21:
|
|
923
922
|
case "end":
|
|
924
923
|
return _context6.stop();
|
|
925
924
|
}
|
|
926
|
-
}, _callee6, this, [[0,
|
|
925
|
+
}, _callee6, this, [[0, 17]]);
|
|
927
926
|
}));
|
|
928
927
|
function getUserIdentificationCodeListAsync(_x7) {
|
|
929
928
|
return _getUserIdentificationCodeListAsync.apply(this, arguments);
|
|
@@ -62,13 +62,21 @@ function resolveRequestedDurationMinutes(product, request) {
|
|
|
62
62
|
}
|
|
63
63
|
function resolveRequestedDurationStartTimes(product, request) {
|
|
64
64
|
var _request$durationStar;
|
|
65
|
-
|
|
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));
|
|
@@ -1025,12 +1033,23 @@ export function getProductTimeRanges(projection) {
|
|
|
1025
1033
|
};
|
|
1026
1034
|
}
|
|
1027
1035
|
if (product.kind === 'session' || product.kind === 'venue_slot') {
|
|
1036
|
+
var fixedRanges = getSessionRangesForProduct(projection, product, dateRange);
|
|
1037
|
+
var customRanges = [];
|
|
1038
|
+
var customDurationMinutes = resolveRequestedSessionDurationMinutes(product, request, runtimeOptions.allowSessionCustomRanges === true);
|
|
1039
|
+
var _requestedStartTimes = resolveRequestedDurationStartTimes(product, request, runtimeOptions.allowSessionCustomRanges === true);
|
|
1040
|
+
if (product.kind === 'session' && customDurationMinutes && dateRange.startDate === dateRange.endDate) {
|
|
1041
|
+
_requestedStartTimes.forEach(function (startTime) {
|
|
1042
|
+
var start = toDateTimeInDate(dateRange.startDate, startTime, projection.meta.timezone);
|
|
1043
|
+
if (!Number.isFinite(start)) return;
|
|
1044
|
+
customRanges.push(createDurationTimeRange(product, start, customDurationMinutes, projection, fixedOffsetMinutes));
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1028
1047
|
return {
|
|
1029
1048
|
productId: product.id,
|
|
1030
1049
|
title: product.title,
|
|
1031
1050
|
kind: product.kind,
|
|
1032
1051
|
slotStepMinutes: slotStepMinutes,
|
|
1033
|
-
ranges:
|
|
1052
|
+
ranges: dedupeProductRanges([].concat(_toConsumableArray(fixedRanges), customRanges))
|
|
1034
1053
|
};
|
|
1035
1054
|
}
|
|
1036
1055
|
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[];
|
|
@@ -1388,7 +1388,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
1388
1388
|
// bundle子商品:保存到扁平化Map
|
|
1389
1389
|
processedFlatItemsMap.set(flatItem._id, [_objectSpread(_objectSpread({}, flatItem), {}, {
|
|
1390
1390
|
discount_list: isManualDiscount ? _this4.resolveDiscountListForManualOverride(((_flatItem$bundleItem8 = flatItem.bundleItem) === null || _flatItem$bundleItem8 === void 0 ? void 0 : _flatItem$bundleItem8.discount_list) || []) : _this4.filterDiscountListByType(((_flatItem$bundleItem9 = flatItem.bundleItem) === null || _flatItem$bundleItem9 === void 0 ? void 0 : _flatItem$bundleItem9.discount_list) || [], 'promotion'),
|
|
1391
|
-
price:
|
|
1391
|
+
price: flatItem.bundleItem.price,
|
|
1392
1392
|
bundle_selling_price: (_flatItem$bundleItem$ = flatItem.bundleItem.bundle_selling_price) !== null && _flatItem$bundleItem$ !== void 0 ? _flatItem$bundleItem$ : isManualDiscount ? flatItem.bundleItem.price : flatItem.bundleItem.original_price,
|
|
1393
1393
|
processed: true
|
|
1394
1394
|
})]);
|
|
@@ -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
|
* 找到多个资源的公共可用时间段
|
|
@@ -458,7 +458,19 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
|
|
|
458
458
|
* 加车两阶段主决策(规格弹窗 / 资源编辑 / 直接加车)。
|
|
459
459
|
* 与 ticketBooking `handleSelectProduct` + `handleBooking4Service` 等价。
|
|
460
460
|
*/
|
|
461
|
-
decideAddProduct(item: any, options?: Partial<AddProductDecideContext>):
|
|
461
|
+
decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): {
|
|
462
|
+
action: "reloadCatalog";
|
|
463
|
+
} | {
|
|
464
|
+
action: "add";
|
|
465
|
+
cacheItem: any;
|
|
466
|
+
} | {
|
|
467
|
+
action: "requiresDetail";
|
|
468
|
+
payload: AddProductRequiresDetailPayload;
|
|
469
|
+
} | {
|
|
470
|
+
action: "requiresBookingEdit";
|
|
471
|
+
cacheItem: any;
|
|
472
|
+
payload: import("./utils/addProductDecision").AddProductRequiresBookingEditPayload;
|
|
473
|
+
};
|
|
462
474
|
/** 规格弹窗 callback 后的第二段决策。 */
|
|
463
475
|
decideAfterDetail(cacheItem: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
|
|
464
476
|
/**
|
|
@@ -1030,7 +1030,7 @@ function buildBookingFromAvailabilitySelection(params) {
|
|
|
1030
1030
|
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) {
|
|
1031
1031
|
return assignment.timeSlotId != null;
|
|
1032
1032
|
})) === null || _assignments$find2 === void 0 ? void 0 : _assignments$find2.timeSlotId;
|
|
1033
|
-
if (product.kind === 'session' && scheduleId == null) {
|
|
1033
|
+
if (product.kind === 'session' && candidate.source === 'session_schedule' && scheduleId == null) {
|
|
1034
1034
|
throw new AvailabilityError('REVALIDATION_FAILED', 'session 候选缺少真实 schedule identity', {
|
|
1035
1035
|
productId: product.id,
|
|
1036
1036
|
candidateKey: candidate.key,
|
|
@@ -1039,15 +1039,16 @@ function buildBookingFromAvailabilitySelection(params) {
|
|
|
1039
1039
|
}
|
|
1040
1040
|
var normalizedHolder = holder && _typeof(holder) === 'object' ? cloneDeep(holder) : undefined;
|
|
1041
1041
|
var normalizedHolderIds = Array.isArray(holderIds) ? cloneDeep(holderIds) : holderIds;
|
|
1042
|
-
return _objectSpread(_objectSpread({
|
|
1042
|
+
return _objectSpread(_objectSpread(_objectSpread({
|
|
1043
1043
|
start_date: bookingStartAt.slice(0, 10),
|
|
1044
1044
|
start_time: bookingStartAt.slice(11, 16),
|
|
1045
1045
|
end_date: bookingEndAt.slice(0, 10),
|
|
1046
1046
|
end_time: bookingEndAt.slice(11, 16),
|
|
1047
1047
|
duration: Math.max(1, Math.trunc((endScalar - startScalar) / (60 * 1000))),
|
|
1048
|
-
like_status: 'common'
|
|
1048
|
+
like_status: 'common'
|
|
1049
|
+
}, product.kind === 'session' && candidate.source === 'duration_window' ? {} : {
|
|
1049
1050
|
schedule_id: scheduleId !== null && scheduleId !== void 0 ? scheduleId : 0
|
|
1050
|
-
}, normalizedHolder ? {
|
|
1051
|
+
}), normalizedHolder ? {
|
|
1051
1052
|
holder: normalizedHolder
|
|
1052
1053
|
} : {}), {}, {
|
|
1053
1054
|
resources: assignments.map(function (assignment) {
|
|
@@ -4272,6 +4273,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4272
4273
|
context,
|
|
4273
4274
|
projectionEntry,
|
|
4274
4275
|
contextVersion,
|
|
4276
|
+
isPosAvailabilityRequest,
|
|
4275
4277
|
allowOutsideOperatingHoursForRequestedStartTimes,
|
|
4276
4278
|
_args37 = arguments;
|
|
4277
4279
|
return _regeneratorRuntime().wrap(function _callee37$(_context37) {
|
|
@@ -4285,13 +4287,15 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4285
4287
|
context = _yield$this$ensureAva.context;
|
|
4286
4288
|
projectionEntry = _yield$this$ensureAva.projectionEntry;
|
|
4287
4289
|
contextVersion = context.activeVersion;
|
|
4288
|
-
|
|
4290
|
+
isPosAvailabilityRequest = String((_this$otherParams$pla = (_this$otherParams19 = this.otherParams) === null || _this$otherParams19 === void 0 ? void 0 : _this$otherParams19.platform) !== null && _this$otherParams$pla !== void 0 ? _this$otherParams$pla : '').trim().toLowerCase() === 'pos';
|
|
4291
|
+
allowOutsideOperatingHoursForRequestedStartTimes = isPosAvailabilityRequest && Object.values(request.durationStartTimesByProductId || {}).some(function (startTimes) {
|
|
4289
4292
|
return Array.isArray(startTimes) && startTimes.length > 0;
|
|
4290
4293
|
});
|
|
4291
4294
|
return _context37.abrupt("return", getProjectionProductTimeRanges(projectionEntry.projection, _objectSpread(_objectSpread({}, request), allowOutsideOperatingHoursForRequestedStartTimes ? {
|
|
4292
4295
|
allowOutsideOperatingHoursForRequestedStartTimes: true
|
|
4293
4296
|
} : {}), {
|
|
4294
|
-
evaluatedAt: this.getAvailabilityRuntimeDateTime()
|
|
4297
|
+
evaluatedAt: this.getAvailabilityRuntimeDateTime(),
|
|
4298
|
+
allowSessionCustomRanges: isPosAvailabilityRequest
|
|
4295
4299
|
}).map(function (group) {
|
|
4296
4300
|
return _objectSpread(_objectSpread({}, group), {}, {
|
|
4297
4301
|
ranges: group.ranges.map(function (candidate) {
|
|
@@ -4299,7 +4303,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4299
4303
|
})
|
|
4300
4304
|
});
|
|
4301
4305
|
}));
|
|
4302
|
-
case
|
|
4306
|
+
case 10:
|
|
4303
4307
|
case "end":
|
|
4304
4308
|
return _context37.stop();
|
|
4305
4309
|
}
|
|
@@ -4678,7 +4682,9 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4678
4682
|
durationStartTimesByProductId: _defineProperty({}, String(params.candidate.productId), [candidateStartTime])
|
|
4679
4683
|
}, allowPosAvailabilityOverride ? {
|
|
4680
4684
|
allowOutsideOperatingHoursForRequestedStartTimes: true
|
|
4681
|
-
} : {}) : {}) : {})
|
|
4685
|
+
} : {}) : {}) : {}), {
|
|
4686
|
+
allowSessionCustomRanges: allowPosAvailabilityOverride
|
|
4687
|
+
}).flatMap(function (group) {
|
|
4682
4688
|
return group.ranges;
|
|
4683
4689
|
});
|
|
4684
4690
|
refreshedCandidateBase = refreshedRanges.find(function (candidate) {
|
|
@@ -533,7 +533,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
533
533
|
generateIdempotencyToken(): string;
|
|
534
534
|
syncPaymentsToOrder<T = any>(params: SyncPaymentsToOrderParams): Promise<SyncPaymentsToOrderResult<T>>;
|
|
535
535
|
createOrder(params: CommitOrderParams['query']): {
|
|
536
|
-
type: "
|
|
536
|
+
type: "appointment_booking" | "virtual";
|
|
537
537
|
platform: string;
|
|
538
538
|
sales_channel: string;
|
|
539
539
|
order_sales_channel: string;
|
|
@@ -650,17 +650,20 @@ class WalletPassPaymentImpl {
|
|
|
650
650
|
this.paymentModule.logInfo('[WalletPass] 商品列表为空,跳过获取用户识别码列表');
|
|
651
651
|
return [];
|
|
652
652
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
653
|
+
|
|
654
|
+
// const platform = this.paymentModule.getPlatform();
|
|
655
|
+
// if (platform === 'pc' || platform === 'h5') {
|
|
656
|
+
// this.userIdentificationCodes = [];
|
|
657
|
+
// this.emitEvent(WalletPassHooks.OnUserIdentificationCodesUpdated, {
|
|
658
|
+
// userIdentificationCodes: [],
|
|
659
|
+
// } as OnUserIdentificationCodesUpdatedEventData);
|
|
660
|
+
// this.paymentModule.logInfo(
|
|
661
|
+
// '[WalletPass] 用户端平台跳过获取用户识别码列表',
|
|
662
|
+
// { platform },
|
|
663
|
+
// );
|
|
664
|
+
// return [];
|
|
665
|
+
// }
|
|
666
|
+
|
|
664
667
|
if (typeof newParams.payment_order_id === 'string' && newParams.payment_order_id.startsWith('LOCAL_')) {
|
|
665
668
|
newParams.payment_order_id = undefined;
|
|
666
669
|
}
|
|
@@ -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));
|
|
@@ -919,12 +925,23 @@ function getProductTimeRanges(projection, request = {}, runtimeOptions = {}) {
|
|
|
919
925
|
};
|
|
920
926
|
}
|
|
921
927
|
if (product.kind === 'session' || product.kind === 'venue_slot') {
|
|
928
|
+
const fixedRanges = getSessionRangesForProduct(projection, product, dateRange);
|
|
929
|
+
const customRanges = [];
|
|
930
|
+
const customDurationMinutes = resolveRequestedSessionDurationMinutes(product, request, runtimeOptions.allowSessionCustomRanges === true);
|
|
931
|
+
const requestedStartTimes = resolveRequestedDurationStartTimes(product, request, runtimeOptions.allowSessionCustomRanges === true);
|
|
932
|
+
if (product.kind === 'session' && customDurationMinutes && dateRange.startDate === dateRange.endDate) {
|
|
933
|
+
requestedStartTimes.forEach(startTime => {
|
|
934
|
+
const start = toDateTimeInDate(dateRange.startDate, startTime, projection.meta.timezone);
|
|
935
|
+
if (!Number.isFinite(start)) return;
|
|
936
|
+
customRanges.push(createDurationTimeRange(product, start, customDurationMinutes, projection, fixedOffsetMinutes));
|
|
937
|
+
});
|
|
938
|
+
}
|
|
922
939
|
return {
|
|
923
940
|
productId: product.id,
|
|
924
941
|
title: product.title,
|
|
925
942
|
kind: product.kind,
|
|
926
943
|
slotStepMinutes,
|
|
927
|
-
ranges:
|
|
944
|
+
ranges: dedupeProductRanges([...fixedRanges, ...customRanges])
|
|
928
945
|
};
|
|
929
946
|
}
|
|
930
947
|
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[];
|
|
@@ -1128,7 +1128,7 @@ class RulesModule extends _BaseModule.BaseModule {
|
|
|
1128
1128
|
processedFlatItemsMap.set(flatItem._id, [{
|
|
1129
1129
|
...flatItem,
|
|
1130
1130
|
discount_list: isManualDiscount ? this.resolveDiscountListForManualOverride(flatItem.bundleItem?.discount_list || []) : this.filterDiscountListByType(flatItem.bundleItem?.discount_list || [], 'promotion'),
|
|
1131
|
-
price:
|
|
1131
|
+
price: flatItem.bundleItem.price,
|
|
1132
1132
|
bundle_selling_price: flatItem.bundleItem.bundle_selling_price ?? (isManualDiscount ? flatItem.bundleItem.price : flatItem.bundleItem.original_price),
|
|
1133
1133
|
processed: true
|
|
1134
1134
|
}]);
|
|
@@ -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
|
* 找到多个资源的公共可用时间段
|
|
@@ -458,7 +458,19 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
|
|
|
458
458
|
* 加车两阶段主决策(规格弹窗 / 资源编辑 / 直接加车)。
|
|
459
459
|
* 与 ticketBooking `handleSelectProduct` + `handleBooking4Service` 等价。
|
|
460
460
|
*/
|
|
461
|
-
decideAddProduct(item: any, options?: Partial<AddProductDecideContext>):
|
|
461
|
+
decideAddProduct(item: any, options?: Partial<AddProductDecideContext>): {
|
|
462
|
+
action: "reloadCatalog";
|
|
463
|
+
} | {
|
|
464
|
+
action: "add";
|
|
465
|
+
cacheItem: any;
|
|
466
|
+
} | {
|
|
467
|
+
action: "requiresDetail";
|
|
468
|
+
payload: AddProductRequiresDetailPayload;
|
|
469
|
+
} | {
|
|
470
|
+
action: "requiresBookingEdit";
|
|
471
|
+
cacheItem: any;
|
|
472
|
+
payload: import("./utils/addProductDecision").AddProductRequiresBookingEditPayload;
|
|
473
|
+
};
|
|
462
474
|
/** 规格弹窗 callback 后的第二段决策。 */
|
|
463
475
|
decideAfterDetail(cacheItem: any, options?: Partial<AddProductDecideContext>): import("./utils/addProductDecision").AddProductDecision;
|
|
464
476
|
/**
|
|
@@ -946,7 +946,7 @@ function buildBookingFromAvailabilitySelection(params) {
|
|
|
946
946
|
const endScalar = (0, _localClock.localDateTimeToScalar)((0, _localClock.parseLocalDateTime)(bookingEndAt));
|
|
947
947
|
const scheduleId = candidate.primaryScheduleRef?.scheduleId ?? assignments.find(assignment => assignment.scheduleId != null)?.scheduleId;
|
|
948
948
|
const timeSlotId = candidate.primaryScheduleRef?.timeSlotId ?? assignments.find(assignment => assignment.timeSlotId != null)?.timeSlotId;
|
|
949
|
-
if (product.kind === 'session' && scheduleId == null) {
|
|
949
|
+
if (product.kind === 'session' && candidate.source === 'session_schedule' && scheduleId == null) {
|
|
950
950
|
throw new _ResourcePlanner.AvailabilityError('REVALIDATION_FAILED', 'session 候选缺少真实 schedule identity', {
|
|
951
951
|
productId: product.id,
|
|
952
952
|
candidateKey: candidate.key,
|
|
@@ -962,7 +962,9 @@ function buildBookingFromAvailabilitySelection(params) {
|
|
|
962
962
|
end_time: bookingEndAt.slice(11, 16),
|
|
963
963
|
duration: Math.max(1, Math.trunc((endScalar - startScalar) / (60 * 1000))),
|
|
964
964
|
like_status: 'common',
|
|
965
|
-
|
|
965
|
+
...(product.kind === 'session' && candidate.source === 'duration_window' ? {} : {
|
|
966
|
+
schedule_id: scheduleId ?? 0
|
|
967
|
+
}),
|
|
966
968
|
...(normalizedHolder ? {
|
|
967
969
|
holder: normalizedHolder
|
|
968
970
|
} : {}),
|
|
@@ -2822,14 +2824,16 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
|
|
|
2822
2824
|
projectionEntry
|
|
2823
2825
|
} = await this.ensureAvailabilityContextProjection(contextId, 'get_product_time_ranges');
|
|
2824
2826
|
const contextVersion = context.activeVersion;
|
|
2825
|
-
const
|
|
2827
|
+
const isPosAvailabilityRequest = String(this.otherParams?.platform ?? '').trim().toLowerCase() === 'pos';
|
|
2828
|
+
const allowOutsideOperatingHoursForRequestedStartTimes = isPosAvailabilityRequest && Object.values(request.durationStartTimesByProductId || {}).some(startTimes => Array.isArray(startTimes) && startTimes.length > 0);
|
|
2826
2829
|
return (0, _ResourcePlanner.getProductTimeRanges)(projectionEntry.projection, {
|
|
2827
2830
|
...request,
|
|
2828
2831
|
...(allowOutsideOperatingHoursForRequestedStartTimes ? {
|
|
2829
2832
|
allowOutsideOperatingHoursForRequestedStartTimes: true
|
|
2830
2833
|
} : {})
|
|
2831
2834
|
}, {
|
|
2832
|
-
evaluatedAt: this.getAvailabilityRuntimeDateTime()
|
|
2835
|
+
evaluatedAt: this.getAvailabilityRuntimeDateTime(),
|
|
2836
|
+
allowSessionCustomRanges: isPosAvailabilityRequest
|
|
2833
2837
|
}).map(group => ({
|
|
2834
2838
|
...group,
|
|
2835
2839
|
ranges: group.ranges.map(candidate => this.decorateAvailabilityCandidate(context.contextId, contextVersion, candidate))
|
|
@@ -3100,6 +3104,8 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
|
|
|
3100
3104
|
} : {})
|
|
3101
3105
|
} : {})
|
|
3102
3106
|
} : {})
|
|
3107
|
+
}, {
|
|
3108
|
+
allowSessionCustomRanges: allowPosAvailabilityOverride
|
|
3103
3109
|
}).flatMap(group => group.ranges);
|
|
3104
3110
|
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);
|
|
3105
3111
|
if (!refreshedCandidateBase) {
|