@pisell/pisellos 2.3.87 → 2.3.89
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/types.d.ts +2 -0
- package/dist/modules/Order/utils.js +1 -0
- package/dist/modules/Product/types.d.ts +2 -0
- package/dist/modules/ResourcePlanner/planner.js +54 -17
- package/dist/modules/ResourcePlanner/types.d.ts +3 -0
- package/dist/modules/Rules/index.js +11 -8
- package/dist/solution/BaseSales/types.d.ts +2 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +3 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +7 -1
- package/dist/solution/BaseSales/utils.js +6 -3
- package/dist/solution/BookingByStep/index.d.ts +2 -2
- package/dist/solution/BookingTicket/utils/addProductDecision.js +3 -1
- package/dist/solution/ScanOrder/types.d.ts +2 -0
- package/dist/solution/ScanOrder/utils.js +6 -3
- package/dist/solution/UnifiedBookingSales/index.js +62 -32
- package/lib/model/strategy/adapter/promotion/index.js +46 -1
- package/lib/modules/Order/types.d.ts +2 -0
- package/lib/modules/Order/utils.js +1 -0
- package/lib/modules/Product/types.d.ts +2 -0
- package/lib/modules/ResourcePlanner/planner.js +48 -17
- package/lib/modules/ResourcePlanner/types.d.ts +3 -0
- package/lib/modules/Rules/index.js +8 -6
- package/lib/solution/BaseSales/types.d.ts +2 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +3 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +6 -0
- package/lib/solution/BaseSales/utils.js +3 -0
- package/lib/solution/BookingByStep/index.d.ts +2 -2
- package/lib/solution/BookingTicket/utils/addProductDecision.js +2 -0
- package/lib/solution/ScanOrder/types.d.ts +2 -0
- package/lib/solution/ScanOrder/utils.js +3 -0
- package/lib/solution/UnifiedBookingSales/index.js +37 -1
- package/package.json +1 -1
|
@@ -191,6 +191,8 @@ export interface OrderLocalizedText {
|
|
|
191
191
|
export interface OrderProduct extends OrderProductIdentity {
|
|
192
192
|
order_detail_id: number | null;
|
|
193
193
|
num: number;
|
|
194
|
+
/** Product 或当前 Variant 的生产编码 */
|
|
195
|
+
production_code?: string;
|
|
194
196
|
bundle_edit?: number;
|
|
195
197
|
product_sku: OrderProductSku;
|
|
196
198
|
gift_card?: number;
|
|
@@ -868,6 +868,7 @@ function formatSubmitBundleItems(bundle) {
|
|
|
868
868
|
return {
|
|
869
869
|
is_charge_tax: (_rawBundle$is_charge_ = rawBundle.is_charge_tax) !== null && _rawBundle$is_charge_ !== void 0 ? _rawBundle$is_charge_ : 0,
|
|
870
870
|
bundle_variant_id: (_rawBundle$bundle_var = rawBundle.bundle_variant_id) !== null && _rawBundle$bundle_var !== void 0 ? _rawBundle$bundle_var : 0,
|
|
871
|
+
production_code: rawBundle.production_code,
|
|
871
872
|
num: num,
|
|
872
873
|
quantity: toBundleNumber((_rawBundle$quantity = rawBundle.quantity) !== null && _rawBundle$quantity !== void 0 ? _rawBundle$quantity : rawBundle.num, num),
|
|
873
874
|
extension_id: (_rawBundle$extension_ = rawBundle.extension_id) !== null && _rawBundle$extension_ !== void 0 ? _rawBundle$extension_ : 0,
|
|
@@ -52,6 +52,23 @@ function normalizeBookingCount(bookingCount) {
|
|
|
52
52
|
}
|
|
53
53
|
return normalized;
|
|
54
54
|
}
|
|
55
|
+
function resolveRequestedDurationMinutes(product, request) {
|
|
56
|
+
var _request$durationMinu;
|
|
57
|
+
var configured = Math.max(1, Number(product.durationMinutes || 30) || 30);
|
|
58
|
+
if (product.kind !== 'duration') return configured;
|
|
59
|
+
var override = (_request$durationMinu = request.durationMinutesByProductId) === null || _request$durationMinu === void 0 ? void 0 : _request$durationMinu[String(product.id)];
|
|
60
|
+
var normalized = Number(override);
|
|
61
|
+
return Number.isInteger(normalized) && normalized > 0 ? normalized : configured;
|
|
62
|
+
}
|
|
63
|
+
function resolveRequestedDurationStartTimes(product, request) {
|
|
64
|
+
var _request$durationStar;
|
|
65
|
+
if (product.kind !== 'duration') return [];
|
|
66
|
+
var values = (_request$durationStar = request.durationStartTimesByProductId) === null || _request$durationStar === void 0 ? void 0 : _request$durationStar[String(product.id)];
|
|
67
|
+
if (!Array.isArray(values)) return [];
|
|
68
|
+
return Array.from(new Set(values.filter(function (value) {
|
|
69
|
+
return typeof value === 'string' && /^([01]\d|2[0-3]):[0-5]\d$/.test(value);
|
|
70
|
+
})));
|
|
71
|
+
}
|
|
55
72
|
function toDateTime(value, _timezoneName) {
|
|
56
73
|
try {
|
|
57
74
|
return localDateTimeToScalar(parseLocalDateTime(value));
|
|
@@ -962,11 +979,29 @@ function dedupeProductRanges(ranges) {
|
|
|
962
979
|
return left.startAt.localeCompare(right.startAt);
|
|
963
980
|
});
|
|
964
981
|
}
|
|
982
|
+
function createDurationTimeRange(product, start, durationMinutes, projection, fixedOffsetMinutes) {
|
|
983
|
+
var bookingEnd = addMinutesZoned(start, durationMinutes, projection.meta.timezone);
|
|
984
|
+
return {
|
|
985
|
+
key: "".concat(String(product.id), ":").concat(start, ":").concat(bookingEnd),
|
|
986
|
+
productId: product.id,
|
|
987
|
+
source: 'duration_window',
|
|
988
|
+
startAt: formatDateTime(start, projection.meta.timezone, fixedOffsetMinutes),
|
|
989
|
+
endAt: formatDateTime(bookingEnd, projection.meta.timezone, fixedOffsetMinutes),
|
|
990
|
+
bookingStartAt: formatDateTime(start, projection.meta.timezone, fixedOffsetMinutes),
|
|
991
|
+
bookingEndAt: formatDateTime(bookingEnd, projection.meta.timezone, fixedOffsetMinutes),
|
|
992
|
+
date: formatDate(start, projection.meta.timezone),
|
|
993
|
+
startTime: formatTime(start, projection.meta.timezone),
|
|
994
|
+
endTime: formatTime(bookingEnd, projection.meta.timezone),
|
|
995
|
+
timezone: projection.meta.timezone,
|
|
996
|
+
scheduleRefs: []
|
|
997
|
+
};
|
|
998
|
+
}
|
|
965
999
|
export function getProductTimeRanges(projection) {
|
|
966
1000
|
var _extractFixedOffsetMi3, _request$productIds;
|
|
967
1001
|
var request = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
968
1002
|
var normalizedPartySize = normalizePartySize(request.partySize);
|
|
969
1003
|
var dateRange = resolveProjectionDateRange(projection, request.dateRange);
|
|
1004
|
+
var slotStepMinutes = projection.meta.defaults.slotStepMinutes;
|
|
970
1005
|
var fixedOffsetMinutes = (_extractFixedOffsetMi3 = extractFixedOffsetMinutes(projection.meta.now)) !== null && _extractFixedOffsetMi3 !== void 0 ? _extractFixedOffsetMi3 : captureRuntimeOffsetMinutes();
|
|
971
1006
|
var resourceWindowIndex = buildResourceWindowIndex(projection);
|
|
972
1007
|
var filteredProductIdSet = (_request$productIds = request.productIds) !== null && _request$productIds !== void 0 && _request$productIds.length ? new Set(request.productIds.map(String)) : null;
|
|
@@ -978,6 +1013,7 @@ export function getProductTimeRanges(projection) {
|
|
|
978
1013
|
productId: product.id,
|
|
979
1014
|
title: product.title,
|
|
980
1015
|
kind: product.kind,
|
|
1016
|
+
slotStepMinutes: slotStepMinutes,
|
|
981
1017
|
ranges: []
|
|
982
1018
|
};
|
|
983
1019
|
}
|
|
@@ -986,6 +1022,7 @@ export function getProductTimeRanges(projection) {
|
|
|
986
1022
|
productId: product.id,
|
|
987
1023
|
title: product.title,
|
|
988
1024
|
kind: product.kind,
|
|
1025
|
+
slotStepMinutes: slotStepMinutes,
|
|
989
1026
|
ranges: getSessionRangesForProduct(projection, product, dateRange)
|
|
990
1027
|
};
|
|
991
1028
|
}
|
|
@@ -1007,9 +1044,9 @@ export function getProductTimeRanges(projection) {
|
|
|
1007
1044
|
return current === null ? ranges : intersectRangeLists(current, ranges);
|
|
1008
1045
|
}, null) || [] : null;
|
|
1009
1046
|
var baseRanges = resourceRanges === null ? operatingRanges : intersectRangeLists(resourceRanges, operatingRanges);
|
|
1010
|
-
var durationMinutes =
|
|
1011
|
-
var timeSliceMinutes = projection.meta.defaults.slotStepMinutes;
|
|
1047
|
+
var durationMinutes = resolveRequestedDurationMinutes(product, request);
|
|
1012
1048
|
var durationAnchor = ceilToTenMinutes(toDateTime(projection.meta.durationCandidateAnchorAt, projection.meta.timezone), projection.meta.timezone);
|
|
1049
|
+
var requestedStartTimes = resolveRequestedDurationStartTimes(product, request);
|
|
1013
1050
|
var ranges = [];
|
|
1014
1051
|
baseRanges.forEach(function (range) {
|
|
1015
1052
|
if (range.end <= durationAnchor) return;
|
|
@@ -1022,28 +1059,28 @@ export function getProductTimeRanges(projection) {
|
|
|
1022
1059
|
if (bookingEnd > range.end) break;
|
|
1023
1060
|
var bookingDate = formatDate(cursor);
|
|
1024
1061
|
if (bookingDate >= dateRange.startDate && bookingDate <= dateRange.endDate) {
|
|
1025
|
-
ranges.push(
|
|
1026
|
-
key: "".concat(String(product.id), ":").concat(cursor, ":").concat(bookingEnd),
|
|
1027
|
-
productId: product.id,
|
|
1028
|
-
source: 'duration_window',
|
|
1029
|
-
startAt: formatDateTime(cursor, projection.meta.timezone, fixedOffsetMinutes),
|
|
1030
|
-
endAt: formatDateTime(bookingEnd, projection.meta.timezone, fixedOffsetMinutes),
|
|
1031
|
-
bookingStartAt: formatDateTime(cursor, projection.meta.timezone, fixedOffsetMinutes),
|
|
1032
|
-
bookingEndAt: formatDateTime(bookingEnd, projection.meta.timezone, fixedOffsetMinutes),
|
|
1033
|
-
date: formatDate(cursor, projection.meta.timezone),
|
|
1034
|
-
startTime: formatTime(cursor, projection.meta.timezone),
|
|
1035
|
-
endTime: formatTime(bookingEnd, projection.meta.timezone),
|
|
1036
|
-
timezone: projection.meta.timezone,
|
|
1037
|
-
scheduleRefs: []
|
|
1038
|
-
});
|
|
1062
|
+
ranges.push(createDurationTimeRange(product, cursor, durationMinutes, projection, fixedOffsetMinutes));
|
|
1039
1063
|
}
|
|
1040
|
-
cursor = addMinutesZoned(cursor,
|
|
1064
|
+
cursor = addMinutesZoned(cursor, slotStepMinutes, projection.meta.timezone);
|
|
1041
1065
|
}
|
|
1042
1066
|
});
|
|
1067
|
+
if (dateRange.startDate === dateRange.endDate && requestedStartTimes.length > 0) {
|
|
1068
|
+
requestedStartTimes.forEach(function (startTime) {
|
|
1069
|
+
var start = toDateTimeInDate(dateRange.startDate, startTime, projection.meta.timezone);
|
|
1070
|
+
if (!Number.isFinite(start)) return;
|
|
1071
|
+
var end = addMinutesZoned(start, durationMinutes, projection.meta.timezone);
|
|
1072
|
+
var startsInOperatingRange = operatingRanges.some(function (range) {
|
|
1073
|
+
return range.start <= start && start < range.end;
|
|
1074
|
+
});
|
|
1075
|
+
if (!startsInOperatingRange) return;
|
|
1076
|
+
ranges.push(createDurationTimeRange(product, start, durationMinutes, projection, fixedOffsetMinutes));
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1043
1079
|
return {
|
|
1044
1080
|
productId: product.id,
|
|
1045
1081
|
title: product.title,
|
|
1046
1082
|
kind: product.kind,
|
|
1083
|
+
slotStepMinutes: slotStepMinutes,
|
|
1047
1084
|
ranges: dedupeProductRanges(ranges)
|
|
1048
1085
|
};
|
|
1049
1086
|
});
|
|
@@ -211,6 +211,7 @@ export interface ProductTimeRangeGroup {
|
|
|
211
211
|
productId: AvailabilityId;
|
|
212
212
|
title?: string;
|
|
213
213
|
kind: AvailabilityProductKind;
|
|
214
|
+
slotStepMinutes?: number;
|
|
214
215
|
ranges: ProductTimeRange[];
|
|
215
216
|
}
|
|
216
217
|
export interface AvailabilityAssignment extends AvailabilityAbsoluteRange {
|
|
@@ -231,6 +232,8 @@ export interface GetProductTimeRangesRequest {
|
|
|
231
232
|
dateRange?: Partial<AvailabilityDateRange>;
|
|
232
233
|
resourceIds?: AvailabilityId[];
|
|
233
234
|
partySize?: number;
|
|
235
|
+
durationMinutesByProductId?: Record<string, number>;
|
|
236
|
+
durationStartTimesByProductId?: Record<string, string[]>;
|
|
234
237
|
}
|
|
235
238
|
export interface QueryAvailabilityBaseRequest {
|
|
236
239
|
productIds?: AvailabilityId[];
|
|
@@ -2223,7 +2223,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
2223
2223
|
}, {
|
|
2224
2224
|
key: "checkPackageSubItemUsageRules",
|
|
2225
2225
|
value: function checkPackageSubItemUsageRules(discount, flatItem) {
|
|
2226
|
-
var _flatItem$product;
|
|
2226
|
+
var _flatItem$product, _flatItem$originProdu, _flatItem$parentProdu10;
|
|
2227
2227
|
var limitedData = discount.limited_relation_product_data;
|
|
2228
2228
|
var usageRules = limitedData === null || limitedData === void 0 ? void 0 : limitedData.package_sub_item_usage_rules;
|
|
2229
2229
|
var rules = ['original_price'].concat(_toConsumableArray((usageRules === null || usageRules === void 0 ? void 0 : usageRules.rules) || []));
|
|
@@ -2236,7 +2236,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
2236
2236
|
// 套餐适用范围配置
|
|
2237
2237
|
var packageScope = usageRules === null || usageRules === void 0 ? void 0 : usageRules.package_scope;
|
|
2238
2238
|
var _ref18 = packageScope || {},
|
|
2239
|
-
|
|
2239
|
+
_ref18$type = _ref18.type,
|
|
2240
|
+
scopeType = _ref18$type === void 0 ? 'product_all' : _ref18$type,
|
|
2240
2241
|
_ref18$exclude_bundle = _ref18.exclude_bundle_product_ids,
|
|
2241
2242
|
exclude_bundle_product_ids = _ref18$exclude_bundle === void 0 ? [] : _ref18$exclude_bundle,
|
|
2242
2243
|
_ref18$include_bundle = _ref18.include_bundle_product_ids,
|
|
@@ -2246,6 +2247,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
2246
2247
|
var isMainProduct = flatItem.type === 'main'; // 单独购买
|
|
2247
2248
|
var isBundleItem = flatItem.type === 'bundle'; // 套餐中购买
|
|
2248
2249
|
var bundleMainProductId = (_flatItem$product = flatItem.product) === null || _flatItem$product === void 0 ? void 0 : _flatItem$product.product_id;
|
|
2250
|
+
// 主商品id
|
|
2251
|
+
var mainProductId = (flatItem === null || flatItem === void 0 || (_flatItem$originProdu = flatItem.originProduct) === null || _flatItem$originProdu === void 0 || (_flatItem$originProdu = _flatItem$originProdu._productOrigin) === null || _flatItem$originProdu === void 0 ? void 0 : _flatItem$originProdu.id) || (flatItem === null || flatItem === void 0 || (_flatItem$parentProdu10 = flatItem.parentProduct) === null || _flatItem$parentProdu10 === void 0 ? void 0 : _flatItem$parentProdu10.id) || 0;
|
|
2249
2252
|
|
|
2250
2253
|
// 主商品直接可用
|
|
2251
2254
|
if (isMainProduct) {
|
|
@@ -2258,12 +2261,12 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
2258
2261
|
return true; // 单独购买时可用
|
|
2259
2262
|
}
|
|
2260
2263
|
if (isBundleItem) {
|
|
2261
|
-
var _flatItem$bundleItem10, _flatItem$bundleItem11
|
|
2264
|
+
var _flatItem$bundleItem10, _flatItem$bundleItem11;
|
|
2262
2265
|
// 套餐中购买时,判断是否为原价
|
|
2263
2266
|
var priceType = (_flatItem$bundleItem10 = flatItem.bundleItem) === null || _flatItem$bundleItem10 === void 0 ? void 0 : _flatItem$bundleItem10.price_type;
|
|
2264
2267
|
var priceTypeExt = (_flatItem$bundleItem11 = flatItem.bundleItem) === null || _flatItem$bundleItem11 === void 0 ? void 0 : _flatItem$bundleItem11.price_type_ext;
|
|
2265
2268
|
// 主商品id
|
|
2266
|
-
|
|
2269
|
+
// const mainProductId = flatItem?.originProduct?._productOrigin?.id || flatItem?.parentProduct?.id || 0;
|
|
2267
2270
|
// original_price 对应:
|
|
2268
2271
|
// 1. price_type: "markup" && price_type_ext: "product_price"
|
|
2269
2272
|
// markup_price 对应:
|
|
@@ -2288,13 +2291,13 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
2288
2291
|
if (!filter) {
|
|
2289
2292
|
isScopeValid = true;
|
|
2290
2293
|
} else {
|
|
2291
|
-
isScopeValid = !exclude_bundle_product_ids.includes(Number(
|
|
2294
|
+
isScopeValid = !exclude_bundle_product_ids.includes(Number(mainProductId));
|
|
2292
2295
|
}
|
|
2293
2296
|
}
|
|
2294
2297
|
|
|
2295
2298
|
// 包含套餐判断, products值兼容旧数据
|
|
2296
2299
|
if (scopeType === 'specific_packages' || scopeType === 'products') {
|
|
2297
|
-
isScopeValid = include_bundle_product_ids.includes(Number(
|
|
2300
|
+
isScopeValid = include_bundle_product_ids.includes(Number(mainProductId));
|
|
2298
2301
|
}
|
|
2299
2302
|
|
|
2300
2303
|
// 价格和套餐适用范围都符合,则可用
|
|
@@ -2357,13 +2360,13 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
2357
2360
|
if (!filter) {
|
|
2358
2361
|
_isScopeValid = true;
|
|
2359
2362
|
} else {
|
|
2360
|
-
_isScopeValid = !exclude_bundle_product_ids.includes(Number(
|
|
2363
|
+
_isScopeValid = !exclude_bundle_product_ids.includes(Number(mainProductId));
|
|
2361
2364
|
}
|
|
2362
2365
|
}
|
|
2363
2366
|
|
|
2364
2367
|
// 包含套餐判断, products值兼容旧数据
|
|
2365
2368
|
if (scopeType === 'specific_packages' || scopeType === 'products') {
|
|
2366
|
-
_isScopeValid = include_bundle_product_ids.includes(Number(
|
|
2369
|
+
_isScopeValid = include_bundle_product_ids.includes(Number(mainProductId));
|
|
2367
2370
|
}
|
|
2368
2371
|
|
|
2369
2372
|
// 价格和套餐适用范围都符合,则可用
|
|
@@ -112,6 +112,8 @@ export interface BaseSalesUpdateOrderProductQuantityParams extends BaseSalesOrde
|
|
|
112
112
|
export interface BaseSalesOrderProduct extends BaseSalesOrderProductIdentity {
|
|
113
113
|
order_detail_id: number | null;
|
|
114
114
|
num: number;
|
|
115
|
+
/** Product 或当前 Variant 的生产编码 */
|
|
116
|
+
production_code?: string;
|
|
115
117
|
product_sku: BaseSalesProductSku;
|
|
116
118
|
/**
|
|
117
119
|
* 券后 **行 composite 单价** = `metadata.main_product_selling_price`
|
|
@@ -3,6 +3,7 @@ import type { ProductData } from '../../../modules/Product/types';
|
|
|
3
3
|
export interface BaseProductDetailOptionItem {
|
|
4
4
|
option_group_item_id?: number | string;
|
|
5
5
|
option_group_id?: number | string;
|
|
6
|
+
production_code?: string;
|
|
6
7
|
num?: number | string;
|
|
7
8
|
quantity?: number | string;
|
|
8
9
|
price?: number | string;
|
|
@@ -10,6 +11,7 @@ export interface BaseProductDetailOptionItem {
|
|
|
10
11
|
[key: string]: any;
|
|
11
12
|
}
|
|
12
13
|
export interface BaseProductDetailBundleItem {
|
|
14
|
+
production_code?: string;
|
|
13
15
|
option?: BaseProductDetailOptionItem[];
|
|
14
16
|
[key: string]: any;
|
|
15
17
|
}
|
|
@@ -18,6 +20,7 @@ export interface BaseProductDetailPayload {
|
|
|
18
20
|
product_id?: number | string | null;
|
|
19
21
|
variant_id?: number | string | null;
|
|
20
22
|
product_variant_id?: number | string | null;
|
|
23
|
+
production_code?: string;
|
|
21
24
|
quantity?: number | string;
|
|
22
25
|
num?: number | string;
|
|
23
26
|
option?: BaseProductDetailOptionItem[];
|
|
@@ -30,6 +30,10 @@ function toPriceString(value) {
|
|
|
30
30
|
if (!Number.isFinite(parsedValue)) return fallback;
|
|
31
31
|
return parsedValue.toFixed(2);
|
|
32
32
|
}
|
|
33
|
+
function normalizeProductionCode(value) {
|
|
34
|
+
if (value === undefined || value === null) return '';
|
|
35
|
+
return String(value).trim();
|
|
36
|
+
}
|
|
33
37
|
function isBlankValue(value) {
|
|
34
38
|
return value === undefined || value === null || typeof value === 'string' && value.trim() === '';
|
|
35
39
|
}
|
|
@@ -104,7 +108,7 @@ function findVariantById(origin, variantId) {
|
|
|
104
108
|
* 注意:这里不生成 identity,缺省时由 OrderModule 自动补齐。
|
|
105
109
|
*/
|
|
106
110
|
export function transformBaseProductToOrderProduct(params) {
|
|
107
|
-
var _ref10, _ref11, _ref12, _payload$product_id, _ref13, _ref14, _payload$product_vari, _payload$_origin, _payload$_origin2, _ref15, _findVariantById, _ref16, _ref17, _ref18, _ref19, _ref20, _matchedVariant$price, _ref21, _ref22, _payload$price, _ref23, _payload$line_total, _payload$_extend, _ref24, _ref25, _payload$product_sku$, _payload$product_sku, _payload$bundle, _payload$quantity, _payload$_extend2, _extend, _extend2, _ref26, _ref27, _origin$base_price, _ref28, _ref29, _payload$line_total2, _payload$_extend3, _payload$_extend4, _extend3, _payload$_extend5, _payload$_extend6, _ref30, _ref31, _payload$tax_fee, _ref32, _ref33, _payload$is_charge_ta;
|
|
111
|
+
var _ref10, _ref11, _ref12, _payload$product_id, _ref13, _ref14, _payload$product_vari, _payload$_origin, _payload$_origin2, _ref15, _findVariantById, _origin$production_co, _ref16, _ref17, _ref18, _ref19, _ref20, _matchedVariant$price, _ref21, _ref22, _payload$price, _ref23, _payload$line_total, _payload$_extend, _ref24, _ref25, _payload$product_sku$, _payload$product_sku, _payload$bundle, _payload$quantity, _payload$_extend2, _extend, _extend2, _ref26, _ref27, _origin$base_price, _ref28, _ref29, _payload$line_total2, _payload$_extend3, _payload$_extend4, _extend3, _payload$_extend5, _payload$_extend6, _ref30, _ref31, _payload$tax_fee, _ref32, _ref33, _payload$is_charge_ta;
|
|
108
112
|
var payload = params.payload,
|
|
109
113
|
_params$fallbackProdu = params.fallbackProductId,
|
|
110
114
|
fallbackProductId = _params$fallbackProdu === void 0 ? null : _params$fallbackProdu;
|
|
@@ -116,6 +120,7 @@ export function transformBaseProductToOrderProduct(params) {
|
|
|
116
120
|
var callbackOrigin = payload.origin || ((_payload$_origin = payload._origin) === null || _payload$_origin === void 0 ? void 0 : _payload$_origin.sourceProduct) || ((_payload$_origin2 = payload._origin) === null || _payload$_origin2 === void 0 ? void 0 : _payload$_origin2.sourceItem) || payload._origin || {};
|
|
117
121
|
var origin = _objectSpread(_objectSpread({}, sourceProduct || {}), callbackOrigin || {});
|
|
118
122
|
var matchedVariant = (_ref15 = (_findVariantById = findVariantById(callbackOrigin, productVariantId)) !== null && _findVariantById !== void 0 ? _findVariantById : findVariantById(sourceProduct, productVariantId)) !== null && _ref15 !== void 0 ? _ref15 : findVariantById(origin, productVariantId);
|
|
123
|
+
var productionCode = normalizeProductionCode(Object.prototype.hasOwnProperty.call(payload, 'production_code') ? payload.production_code : productVariantId > 0 ? matchedVariant === null || matchedVariant === void 0 ? void 0 : matchedVariant.production_code : (_origin$production_co = origin === null || origin === void 0 ? void 0 : origin.production_code) !== null && _origin$production_co !== void 0 ? _origin$production_co : sourceProduct === null || sourceProduct === void 0 ? void 0 : sourceProduct.production_code);
|
|
119
124
|
var hasPriceOverride = payload.price_override !== undefined && payload.price_override !== null && payload.price_override !== '';
|
|
120
125
|
// 手动改价后 payload.price 是分摊后的主商品售价,不能再作为券前 source。
|
|
121
126
|
// 此时优先从商品/variant 快照读取目录价;售价仍由 line_total - bundle 推导。
|
|
@@ -198,6 +203,7 @@ export function transformBaseProductToOrderProduct(params) {
|
|
|
198
203
|
return _objectSpread(_objectSpread({
|
|
199
204
|
product_id: productId,
|
|
200
205
|
product_variant_id: productVariantId,
|
|
206
|
+
production_code: productionCode,
|
|
201
207
|
unique_identification_number: uniqueIdentificationNumber ? String(uniqueIdentificationNumber) : undefined,
|
|
202
208
|
num: resolvedQuantity,
|
|
203
209
|
product_sku: _objectSpread(_objectSpread({}, payload.product_sku && _typeof(payload.product_sku) === 'object' ? payload.product_sku : {}), {}, {
|
|
@@ -256,11 +256,14 @@ export function normalizeOrderProduct(product) {
|
|
|
256
256
|
sellingPrice: composedSellingPrice,
|
|
257
257
|
quantity: getSafeProductNum(product.num)
|
|
258
258
|
});
|
|
259
|
-
return {
|
|
259
|
+
return _objectSpread(_objectSpread({
|
|
260
260
|
order_detail_id: product.order_detail_id || null,
|
|
261
261
|
product_id: product.product_id,
|
|
262
262
|
num: getSafeProductNum(product.num),
|
|
263
|
-
product_variant_id: product.product_variant_id
|
|
263
|
+
product_variant_id: product.product_variant_id
|
|
264
|
+
}, product.production_code !== undefined && product.production_code !== null ? {
|
|
265
|
+
production_code: String(product.production_code).trim()
|
|
266
|
+
} : {}), {}, {
|
|
264
267
|
product_sku: productSku,
|
|
265
268
|
selling_price: composedSellingPrice,
|
|
266
269
|
original_price: finalOriginalPrice,
|
|
@@ -270,5 +273,5 @@ export function normalizeOrderProduct(product) {
|
|
|
270
273
|
product_bundle: normalizedBundle,
|
|
271
274
|
metadata: metadata,
|
|
272
275
|
note: product.note != null ? String(product.note) : ''
|
|
273
|
-
};
|
|
276
|
+
});
|
|
274
277
|
}
|
|
@@ -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 | 2 | 1 | 3 | 4 | 5 | 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: "lots_of_space" | "filling_up_fast" | "sold_out";
|
|
349
349
|
}[];
|
|
350
350
|
/**
|
|
351
351
|
* 找到多个资源的公共可用时间段
|
|
@@ -319,7 +319,7 @@ export function transformDetailToProductAndBooking(cacheItem, ctx) {
|
|
|
319
319
|
* 把 cacheItem._extend.other 中的字段 + 顶层运行态拼成 `BaseProductDetailPayload`。
|
|
320
320
|
*/
|
|
321
321
|
function buildBasePayloadFromCacheItem(cacheItem, ctx) {
|
|
322
|
-
var _cacheItem$_extend, _cacheItem$_extend$qu, _cacheItem$_extend2, _cacheItem$product_id, _cacheItem$id, _ref5, _other$product_varian, _extend$skuValue, _extend$_skuValue, _extend$price, _extend$price2;
|
|
322
|
+
var _cacheItem$_extend, _cacheItem$_extend$qu, _cacheItem$_extend2, _cacheItem$product_id, _cacheItem$id, _ref5, _other$product_varian, _other$production_cod, _extend$skuValue, _extend$_skuValue, _extend$price, _extend$price2;
|
|
323
323
|
var other = (cacheItem === null || cacheItem === void 0 || (_cacheItem$_extend = cacheItem._extend) === null || _cacheItem$_extend === void 0 ? void 0 : _cacheItem$_extend.other) || {};
|
|
324
324
|
var quantity = (ctx === null || ctx === void 0 ? void 0 : ctx.quantity) != null && ctx.quantity > 0 ? ctx.quantity : (_cacheItem$_extend$qu = cacheItem === null || cacheItem === void 0 || (_cacheItem$_extend2 = cacheItem._extend) === null || _cacheItem$_extend2 === void 0 ? void 0 : _cacheItem$_extend2.quantity) !== null && _cacheItem$_extend$qu !== void 0 ? _cacheItem$_extend$qu : 1;
|
|
325
325
|
var resolvedPid = (_cacheItem$product_id = cacheItem === null || cacheItem === void 0 ? void 0 : cacheItem.product_id) !== null && _cacheItem$product_id !== void 0 ? _cacheItem$product_id : cacheItem === null || cacheItem === void 0 ? void 0 : cacheItem.id;
|
|
@@ -329,6 +329,8 @@ function buildBasePayloadFromCacheItem(cacheItem, ctx) {
|
|
|
329
329
|
id: (_cacheItem$id = cacheItem === null || cacheItem === void 0 ? void 0 : cacheItem.id) !== null && _cacheItem$id !== void 0 ? _cacheItem$id : cacheItem === null || cacheItem === void 0 ? void 0 : cacheItem.product_id,
|
|
330
330
|
product_id: resolvedPid,
|
|
331
331
|
variant_id: (_ref5 = (_other$product_varian = other === null || other === void 0 ? void 0 : other.product_variant_id) !== null && _other$product_varian !== void 0 ? _other$product_varian : other === null || other === void 0 ? void 0 : other.variant_id) !== null && _ref5 !== void 0 ? _ref5 : 0,
|
|
332
|
+
// SKUOptionsSelection 已按 Product / Variant 解析好主商品编码;显式空串也需保留。
|
|
333
|
+
production_code: (_other$production_cod = other === null || other === void 0 ? void 0 : other.production_code) !== null && _other$production_cod !== void 0 ? _other$production_cod : cacheItem === null || cacheItem === void 0 ? void 0 : cacheItem.production_code,
|
|
332
334
|
quantity: quantity,
|
|
333
335
|
// 规格弹窗本次选择是 option 权威源,避免目录/旧订单里的空 option 覆盖它。
|
|
334
336
|
product_sku: productSku ? _objectSpread(_objectSpread({}, productSku), {}, {
|
|
@@ -44,6 +44,8 @@ export interface ScanOrderProductSku {
|
|
|
44
44
|
export interface ScanOrderOrderProduct extends ScanOrderOrderProductIdentity {
|
|
45
45
|
order_detail_id: number | null;
|
|
46
46
|
num: number;
|
|
47
|
+
/** Product 或当前 Variant 的生产编码 */
|
|
48
|
+
production_code?: string;
|
|
47
49
|
product_sku: ScanOrderProductSku;
|
|
48
50
|
/**
|
|
49
51
|
* 券后 **行 composite 单价** = `metadata.main_product_selling_price`
|
|
@@ -660,11 +660,14 @@ export function normalizeOrderProduct(product) {
|
|
|
660
660
|
sellingPrice: composedSellingPrice,
|
|
661
661
|
quantity: getSafeProductNum(product.num)
|
|
662
662
|
});
|
|
663
|
-
return {
|
|
663
|
+
return _objectSpread(_objectSpread({
|
|
664
664
|
order_detail_id: product.order_detail_id || null,
|
|
665
665
|
product_id: product.product_id,
|
|
666
666
|
num: getSafeProductNum(product.num),
|
|
667
|
-
product_variant_id: product.product_variant_id
|
|
667
|
+
product_variant_id: product.product_variant_id
|
|
668
|
+
}, product.production_code !== undefined && product.production_code !== null ? {
|
|
669
|
+
production_code: String(product.production_code).trim()
|
|
670
|
+
} : {}), {}, {
|
|
668
671
|
product_sku: productSku,
|
|
669
672
|
selling_price: composedSellingPrice,
|
|
670
673
|
original_price: manualOriginalPrice,
|
|
@@ -674,7 +677,7 @@ export function normalizeOrderProduct(product) {
|
|
|
674
677
|
product_bundle: normalizedBundle,
|
|
675
678
|
metadata: metadata,
|
|
676
679
|
note: product.note != null ? String(product.note) : ''
|
|
677
|
-
};
|
|
680
|
+
});
|
|
678
681
|
}
|
|
679
682
|
|
|
680
683
|
/**
|
|
@@ -52,6 +52,30 @@ function normalizePositiveInteger(value) {
|
|
|
52
52
|
if (!Number.isInteger(normalized) || normalized <= 0) return undefined;
|
|
53
53
|
return normalized;
|
|
54
54
|
}
|
|
55
|
+
function getCandidateDurationMinutes(candidate) {
|
|
56
|
+
var startAt = candidate.bookingStartAt || candidate.startAt;
|
|
57
|
+
var endAt = candidate.bookingEndAt || candidate.endAt;
|
|
58
|
+
try {
|
|
59
|
+
var start = localDateTimeToScalar(parseLocalDateTime(startAt));
|
|
60
|
+
var end = localDateTimeToScalar(parseLocalDateTime(endAt));
|
|
61
|
+
var minutes = Math.round((end - start) / 60000);
|
|
62
|
+
return Number.isInteger(minutes) && minutes > 0 ? minutes : undefined;
|
|
63
|
+
} catch (_error) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function getCandidateStartTime(candidate) {
|
|
68
|
+
if (/^([01]\d|2[0-3]):[0-5]\d$/.test(candidate.startTime || '')) {
|
|
69
|
+
return candidate.startTime;
|
|
70
|
+
}
|
|
71
|
+
var startAt = candidate.bookingStartAt || candidate.startAt;
|
|
72
|
+
try {
|
|
73
|
+
var start = parseLocalDateTime(startAt);
|
|
74
|
+
return "".concat(String(start.hour).padStart(2, '0'), ":").concat(String(start.minute).padStart(2, '0'));
|
|
75
|
+
} catch (_error) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
55
79
|
function isRecord(value) {
|
|
56
80
|
return !!value && _typeof(value) === 'object' && !Array.isArray(value);
|
|
57
81
|
}
|
|
@@ -4332,7 +4356,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4332
4356
|
key: "commitAvailabilitySelection",
|
|
4333
4357
|
value: (function () {
|
|
4334
4358
|
var _commitAvailabilitySelection = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee37(contextId, params) {
|
|
4335
|
-
var normalizedContextId, _params$bookingCount, _ref46, _params$orderProduct$, _params$orderProduct, _params$orderProduct2, _params$orderProduct3, _params$orderProduct$2, _params$orderProduct4, _params$orderProduct5, _editingLine$product_, _baseProjection$meta$, _refreshedProjection$, _baseProjection$meta$2, _this$otherParams$pla, _this$otherParams17, _ref47, _params$orderProduct$3, _params$orderProduct6, _existingBooking$meta, _ref48, _ref49, _params$orderProduct$4, _params$orderProduct7, _params$orderProduct8, _existingBooking$meta2, _existingBooking$hold, bookingCount, orderProductQuantity, partySize, _yield$this$ensureAva3, context, projectionEntry, refreshed, boundEditingUids, orderProductId, editingLine, _editingLine$product_2, baseProjection, commitWriteGuard, prepareParams, fallbackResources, commitSnapshot, refreshedProjection, _baseProjection$meta$3, latestContext, refreshedRanges, refreshedCandidateBase, product, validation, allowPosAvailabilityOverride, forced, capacityConflict, revalidationEntry, revalidatedContext, refreshedCandidate, existingBooking, existingBookingUid, booking, transformed, productLineUid, bookingUid, productLineUids, bookingUids, _transformed$product_, _transformed$product_2, _transformed$product_3, _ref50, _transformed$product_4, _this$getTempOrder4, _this$getTempOrder5, _this$getTempOrder6, beforeProductLineUids, beforeBookingUids, products, addedLines, addedBookings, nextContext, result;
|
|
4359
|
+
var normalizedContextId, _params$bookingCount, _ref46, _params$orderProduct$, _params$orderProduct, _params$orderProduct2, _params$orderProduct3, _params$orderProduct$2, _params$orderProduct4, _params$orderProduct5, _editingLine$product_, _baseProjection$meta$, _refreshedProjection$, _baseProjection$meta$2, _this$otherParams$pla, _this$otherParams17, _ref47, _params$orderProduct$3, _params$orderProduct6, _existingBooking$meta, _ref48, _ref49, _params$orderProduct$4, _params$orderProduct7, _params$orderProduct8, _existingBooking$meta2, _existingBooking$hold, bookingCount, orderProductQuantity, partySize, _yield$this$ensureAva3, context, projectionEntry, refreshed, boundEditingUids, orderProductId, editingLine, _editingLine$product_2, baseProjection, commitWriteGuard, prepareParams, fallbackResources, commitSnapshot, refreshedProjection, _baseProjection$meta$3, latestContext, candidateDurationMinutes, candidateStartTime, refreshedRanges, refreshedCandidateBase, product, validation, allowPosAvailabilityOverride, forced, capacityConflict, revalidationEntry, revalidatedContext, refreshedCandidate, existingBooking, existingBookingUid, booking, transformed, productLineUid, bookingUid, productLineUids, bookingUids, _transformed$product_, _transformed$product_2, _transformed$product_3, _ref50, _transformed$product_4, _this$getTempOrder4, _this$getTempOrder5, _this$getTempOrder6, beforeProductLineUids, beforeBookingUids, products, addedLines, addedBookings, nextContext, result;
|
|
4336
4360
|
return _regeneratorRuntime().wrap(function _callee37$(_context37) {
|
|
4337
4361
|
while (1) switch (_context37.prev = _context37.next) {
|
|
4338
4362
|
case 0:
|
|
@@ -4560,20 +4584,26 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4560
4584
|
});
|
|
4561
4585
|
case 67:
|
|
4562
4586
|
this.assertAvailabilityCommitWriteCAS(commitWriteGuard);
|
|
4563
|
-
|
|
4587
|
+
candidateDurationMinutes = getCandidateDurationMinutes(params.candidate);
|
|
4588
|
+
candidateStartTime = getCandidateStartTime(params.candidate);
|
|
4589
|
+
refreshedRanges = getProjectionProductTimeRanges(refreshedProjection, _objectSpread({
|
|
4564
4590
|
productIds: [params.candidate.productId],
|
|
4565
4591
|
dateRange: {
|
|
4566
4592
|
startDate: params.candidate.startAt.slice(0, 10),
|
|
4567
4593
|
endDate: params.candidate.startAt.slice(0, 10)
|
|
4568
4594
|
}
|
|
4569
|
-
}
|
|
4595
|
+
}, candidateDurationMinutes ? _objectSpread({
|
|
4596
|
+
durationMinutesByProductId: _defineProperty({}, String(params.candidate.productId), candidateDurationMinutes)
|
|
4597
|
+
}, candidateStartTime ? {
|
|
4598
|
+
durationStartTimesByProductId: _defineProperty({}, String(params.candidate.productId), [candidateStartTime])
|
|
4599
|
+
} : {}) : {})).flatMap(function (group) {
|
|
4570
4600
|
return group.ranges;
|
|
4571
4601
|
});
|
|
4572
4602
|
refreshedCandidateBase = refreshedRanges.find(function (candidate) {
|
|
4573
4603
|
return candidate.startAt === params.candidate.startAt && candidate.endAt === params.candidate.endAt && candidate.bookingStartAt === params.candidate.bookingStartAt && candidate.bookingEndAt === params.candidate.bookingEndAt;
|
|
4574
4604
|
});
|
|
4575
4605
|
if (refreshedCandidateBase) {
|
|
4576
|
-
_context37.next =
|
|
4606
|
+
_context37.next = 74;
|
|
4577
4607
|
break;
|
|
4578
4608
|
}
|
|
4579
4609
|
throw new AvailabilityError('REVALIDATION_FAILED', '缓存重校验后候选时间已不在商品配置中', {
|
|
@@ -4581,18 +4611,18 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4581
4611
|
candidate: params.candidate,
|
|
4582
4612
|
refreshedSnapshotId: refreshedProjection.meta.snapshotId
|
|
4583
4613
|
});
|
|
4584
|
-
case
|
|
4614
|
+
case 74:
|
|
4585
4615
|
product = refreshedProjection.products.find(function (item) {
|
|
4586
4616
|
return sameAvailabilityId(item.id, refreshedCandidateBase.productId);
|
|
4587
4617
|
});
|
|
4588
4618
|
if (product) {
|
|
4589
|
-
_context37.next =
|
|
4619
|
+
_context37.next = 77;
|
|
4590
4620
|
break;
|
|
4591
4621
|
}
|
|
4592
4622
|
throw new AvailabilityError('REVALIDATION_FAILED', '缓存重校验后商品不在 projection 中', {
|
|
4593
4623
|
productId: refreshedCandidateBase.productId
|
|
4594
4624
|
});
|
|
4595
|
-
case
|
|
4625
|
+
case 77:
|
|
4596
4626
|
validation = validateAvailabilitySelection(refreshedProjection, {
|
|
4597
4627
|
candidate: refreshedCandidateBase,
|
|
4598
4628
|
requirementSelections: params.requirementSelections,
|
|
@@ -4621,7 +4651,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4621
4651
|
});
|
|
4622
4652
|
}
|
|
4623
4653
|
if (validation.ok) {
|
|
4624
|
-
_context37.next =
|
|
4654
|
+
_context37.next = 83;
|
|
4625
4655
|
break;
|
|
4626
4656
|
}
|
|
4627
4657
|
capacityConflict = validation.conflicts.find(function (conflict) {
|
|
@@ -4631,7 +4661,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4631
4661
|
validation: validation,
|
|
4632
4662
|
refreshedSnapshotId: refreshedProjection.meta.snapshotId
|
|
4633
4663
|
});
|
|
4634
|
-
case
|
|
4664
|
+
case 83:
|
|
4635
4665
|
// Revalidation failure must leave the caller's candidate reusable. Only publish the
|
|
4636
4666
|
// refreshed projection/version after candidate and resource validation has passed;
|
|
4637
4667
|
// otherwise a second Confirm from the still-open modal would incorrectly become stale.
|
|
@@ -4644,7 +4674,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4644
4674
|
incrementVersion: true
|
|
4645
4675
|
});
|
|
4646
4676
|
revalidatedContext = this.getAvailabilityContextEntry(normalizedContextId);
|
|
4647
|
-
_context37.next =
|
|
4677
|
+
_context37.next = 87;
|
|
4648
4678
|
return this.emitAvailabilityDiagnostic({
|
|
4649
4679
|
action: 'refresh',
|
|
4650
4680
|
contextId: normalizedContextId,
|
|
@@ -4655,7 +4685,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4655
4685
|
previousOrderRevision: baseProjection.meta.orderRevision,
|
|
4656
4686
|
reason: 'commit_cached_occupancy_revalidation'
|
|
4657
4687
|
});
|
|
4658
|
-
case
|
|
4688
|
+
case 87:
|
|
4659
4689
|
commitWriteGuard = {
|
|
4660
4690
|
contextId: normalizedContextId,
|
|
4661
4691
|
expectedVersion: revalidatedContext.activeVersion,
|
|
@@ -4667,13 +4697,13 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4667
4697
|
existingBooking = editingLine ? this.findLinkedBooking(editingLine) : undefined;
|
|
4668
4698
|
existingBookingUid = existingBooking ? getBookingUid(existingBooking) : '';
|
|
4669
4699
|
if (!(params.mode === 'edit' && !existingBookingUid)) {
|
|
4670
|
-
_context37.next =
|
|
4700
|
+
_context37.next = 93;
|
|
4671
4701
|
break;
|
|
4672
4702
|
}
|
|
4673
4703
|
throw new AvailabilityError('PRODUCT_LINE_NOT_FOUND', '编辑商品行缺少关联 booking', {
|
|
4674
4704
|
productLineUid: params.productLineUid
|
|
4675
4705
|
});
|
|
4676
|
-
case
|
|
4706
|
+
case 93:
|
|
4677
4707
|
this.assertAvailabilityCommitWriteCAS(commitWriteGuard);
|
|
4678
4708
|
booking = buildBookingFromAvailabilitySelection({
|
|
4679
4709
|
assignments: validation.assignments,
|
|
@@ -4689,13 +4719,13 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4689
4719
|
quantity: bookingCount
|
|
4690
4720
|
}), 'unified_booking_sales', product);
|
|
4691
4721
|
if (transformed) {
|
|
4692
|
-
_context37.next =
|
|
4722
|
+
_context37.next = 98;
|
|
4693
4723
|
break;
|
|
4694
4724
|
}
|
|
4695
4725
|
throw new AvailabilityError('INVALID_TARGET_FILTER', 'orderProduct 无法转换为订单行', {
|
|
4696
4726
|
orderProduct: params.orderProduct
|
|
4697
4727
|
});
|
|
4698
|
-
case
|
|
4728
|
+
case 98:
|
|
4699
4729
|
transformed.num = bookingCount;
|
|
4700
4730
|
transformed.metadata = _objectSpread(_objectSpread({}, transformed.metadata || {}), {}, {
|
|
4701
4731
|
unified_booking_sales: true,
|
|
@@ -4708,7 +4738,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4708
4738
|
productLineUids = [];
|
|
4709
4739
|
bookingUids = [];
|
|
4710
4740
|
if (!(params.mode === 'edit' && editingLine && params.productLineUid)) {
|
|
4711
|
-
_context37.next =
|
|
4741
|
+
_context37.next = 117;
|
|
4712
4742
|
break;
|
|
4713
4743
|
}
|
|
4714
4744
|
transformed.product_sku = (_transformed$product_ = transformed.product_sku) !== null && _transformed$product_ !== void 0 ? _transformed$product_ : editingLine.product_sku;
|
|
@@ -4718,7 +4748,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4718
4748
|
unique_identification_number: params.productLineUid,
|
|
4719
4749
|
booking_uid: existingBookingUid
|
|
4720
4750
|
});
|
|
4721
|
-
_context37.next =
|
|
4751
|
+
_context37.next = 111;
|
|
4722
4752
|
return this.updateOrderProduct(_objectSpread(_objectSpread({
|
|
4723
4753
|
product_id: (_transformed$product_3 = transformed.product_id) !== null && _transformed$product_3 !== void 0 ? _transformed$product_3 : editingLine.product_id,
|
|
4724
4754
|
product_variant_id: (_ref50 = (_transformed$product_4 = transformed.product_variant_id) !== null && _transformed$product_4 !== void 0 ? _transformed$product_4 : editingLine.product_variant_id) !== null && _ref50 !== void 0 ? _ref50 : 0,
|
|
@@ -4730,23 +4760,23 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4730
4760
|
} : {}), params.allowBookingDiscountReapply !== undefined ? {
|
|
4731
4761
|
allow_booking_discount_reapply: params.allowBookingDiscountReapply
|
|
4732
4762
|
} : {}));
|
|
4733
|
-
case
|
|
4763
|
+
case 111:
|
|
4734
4764
|
productLineUid = params.productLineUid;
|
|
4735
4765
|
bookingUid = existingBookingUid;
|
|
4736
4766
|
productLineUids = [productLineUid];
|
|
4737
4767
|
bookingUids = [bookingUid];
|
|
4738
|
-
_context37.next =
|
|
4768
|
+
_context37.next = 129;
|
|
4739
4769
|
break;
|
|
4740
|
-
case
|
|
4770
|
+
case 117:
|
|
4741
4771
|
beforeProductLineUids = new Set((((_this$getTempOrder4 = this.getTempOrder()) === null || _this$getTempOrder4 === void 0 ? void 0 : _this$getTempOrder4.products) || []).map(function (line) {
|
|
4742
4772
|
return getProductLineUid(line);
|
|
4743
4773
|
}).filter(Boolean));
|
|
4744
4774
|
beforeBookingUids = new Set((((_this$getTempOrder5 = this.getTempOrder()) === null || _this$getTempOrder5 === void 0 ? void 0 : _this$getTempOrder5.bookings) || []).map(function (item) {
|
|
4745
4775
|
return getBookingUid(item);
|
|
4746
4776
|
}).filter(Boolean));
|
|
4747
|
-
_context37.next =
|
|
4777
|
+
_context37.next = 121;
|
|
4748
4778
|
return this.addProductToOrder(transformed, booking);
|
|
4749
|
-
case
|
|
4779
|
+
case 121:
|
|
4750
4780
|
products = _context37.sent;
|
|
4751
4781
|
addedLines = products.filter(function (line) {
|
|
4752
4782
|
var _line$product_id, _line$metadata;
|
|
@@ -4770,7 +4800,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4770
4800
|
}
|
|
4771
4801
|
productLineUid = productLineUids[productLineUids.length - 1] || '';
|
|
4772
4802
|
bookingUid = bookingUids[bookingUids.length - 1] || '';
|
|
4773
|
-
case
|
|
4803
|
+
case 129:
|
|
4774
4804
|
this.invalidateAvailabilityContextsAfterCommit();
|
|
4775
4805
|
nextContext = this.getAvailabilityContextEntry(normalizedContextId);
|
|
4776
4806
|
result = {
|
|
@@ -4784,21 +4814,21 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4784
4814
|
productLineUids: productLineUids,
|
|
4785
4815
|
bookingUids: bookingUids
|
|
4786
4816
|
};
|
|
4787
|
-
_context37.next =
|
|
4817
|
+
_context37.next = 134;
|
|
4788
4818
|
return this.core.effects.emit("".concat(this.name, ":").concat(UnifiedBookingSalesHooks.onAvailabilitySelectionCommitted), result);
|
|
4789
|
-
case
|
|
4819
|
+
case 134:
|
|
4790
4820
|
return _context37.abrupt("return", result);
|
|
4791
|
-
case
|
|
4792
|
-
_context37.prev =
|
|
4793
|
-
_context37.next =
|
|
4821
|
+
case 135:
|
|
4822
|
+
_context37.prev = 135;
|
|
4823
|
+
_context37.next = 138;
|
|
4794
4824
|
return this.releaseAvailabilityCommitLock(normalizedContextId);
|
|
4795
|
-
case
|
|
4796
|
-
return _context37.finish(
|
|
4797
|
-
case
|
|
4825
|
+
case 138:
|
|
4826
|
+
return _context37.finish(135);
|
|
4827
|
+
case 139:
|
|
4798
4828
|
case "end":
|
|
4799
4829
|
return _context37.stop();
|
|
4800
4830
|
}
|
|
4801
|
-
}, _callee37, this, [[5,,
|
|
4831
|
+
}, _callee37, this, [[5,, 135, 139]]);
|
|
4802
4832
|
}));
|
|
4803
4833
|
function commitAvailabilitySelection(_x32, _x33) {
|
|
4804
4834
|
return _commitAvailabilitySelection.apply(this, arguments);
|
|
@@ -1 +1,46 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "BUY_X_GET_Y_FREE_STRATEGY", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _examples.BUY_X_GET_Y_FREE_STRATEGY;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "ITEM_REWARD_STRATEGY", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () {
|
|
15
|
+
return _examples.ITEM_REWARD_STRATEGY;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(exports, "PromotionAdapter", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () {
|
|
21
|
+
return _adapter.PromotionAdapter;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(exports, "PromotionEvaluator", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function () {
|
|
27
|
+
return _evaluator.PromotionEvaluator;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
Object.defineProperty(exports, "X_ITEMS_FOR_Y_PRICE_STRATEGY", {
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: function () {
|
|
33
|
+
return _examples.X_ITEMS_FOR_Y_PRICE_STRATEGY;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
Object.defineProperty(exports, "default", {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function () {
|
|
39
|
+
return _adapter.default;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
var _evaluator = require("./evaluator");
|
|
43
|
+
var _adapter = _interopRequireWildcard(require("./adapter"));
|
|
44
|
+
var _examples = require("./examples");
|
|
45
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
46
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
@@ -191,6 +191,8 @@ export interface OrderLocalizedText {
|
|
|
191
191
|
export interface OrderProduct extends OrderProductIdentity {
|
|
192
192
|
order_detail_id: number | null;
|
|
193
193
|
num: number;
|
|
194
|
+
/** Product 或当前 Variant 的生产编码 */
|
|
195
|
+
production_code?: string;
|
|
194
196
|
bundle_edit?: number;
|
|
195
197
|
product_sku: OrderProductSku;
|
|
196
198
|
gift_card?: number;
|
|
@@ -909,6 +909,7 @@ function formatSubmitBundleItems(bundle) {
|
|
|
909
909
|
return {
|
|
910
910
|
is_charge_tax: rawBundle.is_charge_tax ?? 0,
|
|
911
911
|
bundle_variant_id: rawBundle.bundle_variant_id ?? 0,
|
|
912
|
+
production_code: rawBundle.production_code,
|
|
912
913
|
num,
|
|
913
914
|
quantity: toBundleNumber(rawBundle.quantity ?? rawBundle.num, num),
|
|
914
915
|
extension_id: rawBundle.extension_id ?? 0,
|
|
@@ -48,6 +48,19 @@ function normalizeBookingCount(bookingCount) {
|
|
|
48
48
|
}
|
|
49
49
|
return normalized;
|
|
50
50
|
}
|
|
51
|
+
function resolveRequestedDurationMinutes(product, request) {
|
|
52
|
+
const configured = Math.max(1, Number(product.durationMinutes || 30) || 30);
|
|
53
|
+
if (product.kind !== 'duration') return configured;
|
|
54
|
+
const override = request.durationMinutesByProductId?.[String(product.id)];
|
|
55
|
+
const normalized = Number(override);
|
|
56
|
+
return Number.isInteger(normalized) && normalized > 0 ? normalized : configured;
|
|
57
|
+
}
|
|
58
|
+
function resolveRequestedDurationStartTimes(product, request) {
|
|
59
|
+
if (product.kind !== 'duration') return [];
|
|
60
|
+
const values = request.durationStartTimesByProductId?.[String(product.id)];
|
|
61
|
+
if (!Array.isArray(values)) return [];
|
|
62
|
+
return Array.from(new Set(values.filter(value => typeof value === 'string' && /^([01]\d|2[0-3]):[0-5]\d$/.test(value))));
|
|
63
|
+
}
|
|
51
64
|
function toDateTime(value, _timezoneName) {
|
|
52
65
|
try {
|
|
53
66
|
return (0, _localClock.localDateTimeToScalar)((0, _localClock.parseLocalDateTime)(value));
|
|
@@ -865,9 +878,27 @@ function dedupeProductRanges(ranges) {
|
|
|
865
878
|
});
|
|
866
879
|
return Array.from(map.values()).sort((left, right) => left.startAt.localeCompare(right.startAt));
|
|
867
880
|
}
|
|
881
|
+
function createDurationTimeRange(product, start, durationMinutes, projection, fixedOffsetMinutes) {
|
|
882
|
+
const bookingEnd = addMinutesZoned(start, durationMinutes, projection.meta.timezone);
|
|
883
|
+
return {
|
|
884
|
+
key: `${String(product.id)}:${start}:${bookingEnd}`,
|
|
885
|
+
productId: product.id,
|
|
886
|
+
source: 'duration_window',
|
|
887
|
+
startAt: formatDateTime(start, projection.meta.timezone, fixedOffsetMinutes),
|
|
888
|
+
endAt: formatDateTime(bookingEnd, projection.meta.timezone, fixedOffsetMinutes),
|
|
889
|
+
bookingStartAt: formatDateTime(start, projection.meta.timezone, fixedOffsetMinutes),
|
|
890
|
+
bookingEndAt: formatDateTime(bookingEnd, projection.meta.timezone, fixedOffsetMinutes),
|
|
891
|
+
date: formatDate(start, projection.meta.timezone),
|
|
892
|
+
startTime: formatTime(start, projection.meta.timezone),
|
|
893
|
+
endTime: formatTime(bookingEnd, projection.meta.timezone),
|
|
894
|
+
timezone: projection.meta.timezone,
|
|
895
|
+
scheduleRefs: []
|
|
896
|
+
};
|
|
897
|
+
}
|
|
868
898
|
function getProductTimeRanges(projection, request = {}) {
|
|
869
899
|
const normalizedPartySize = normalizePartySize(request.partySize);
|
|
870
900
|
const dateRange = resolveProjectionDateRange(projection, request.dateRange);
|
|
901
|
+
const slotStepMinutes = projection.meta.defaults.slotStepMinutes;
|
|
871
902
|
const fixedOffsetMinutes = (0, _localClock.extractFixedOffsetMinutes)(projection.meta.now) ?? (0, _localClock.captureRuntimeOffsetMinutes)();
|
|
872
903
|
const resourceWindowIndex = buildResourceWindowIndex(projection);
|
|
873
904
|
const filteredProductIdSet = request.productIds?.length ? new Set(request.productIds.map(String)) : null;
|
|
@@ -877,6 +908,7 @@ function getProductTimeRanges(projection, request = {}) {
|
|
|
877
908
|
productId: product.id,
|
|
878
909
|
title: product.title,
|
|
879
910
|
kind: product.kind,
|
|
911
|
+
slotStepMinutes,
|
|
880
912
|
ranges: []
|
|
881
913
|
};
|
|
882
914
|
}
|
|
@@ -885,6 +917,7 @@ function getProductTimeRanges(projection, request = {}) {
|
|
|
885
917
|
productId: product.id,
|
|
886
918
|
title: product.title,
|
|
887
919
|
kind: product.kind,
|
|
920
|
+
slotStepMinutes,
|
|
888
921
|
ranges: getSessionRangesForProduct(projection, product, dateRange)
|
|
889
922
|
};
|
|
890
923
|
}
|
|
@@ -900,9 +933,9 @@ function getProductTimeRanges(projection, request = {}) {
|
|
|
900
933
|
resourceWindowIndex
|
|
901
934
|
})).reduce((current, ranges) => current === null ? ranges : intersectRangeLists(current, ranges), null) || [] : null;
|
|
902
935
|
const baseRanges = resourceRanges === null ? operatingRanges : intersectRangeLists(resourceRanges, operatingRanges);
|
|
903
|
-
const durationMinutes =
|
|
904
|
-
const timeSliceMinutes = projection.meta.defaults.slotStepMinutes;
|
|
936
|
+
const durationMinutes = resolveRequestedDurationMinutes(product, request);
|
|
905
937
|
const durationAnchor = ceilToTenMinutes(toDateTime(projection.meta.durationCandidateAnchorAt, projection.meta.timezone), projection.meta.timezone);
|
|
938
|
+
const requestedStartTimes = resolveRequestedDurationStartTimes(product, request);
|
|
906
939
|
const ranges = [];
|
|
907
940
|
baseRanges.forEach(range => {
|
|
908
941
|
if (range.end <= durationAnchor) return;
|
|
@@ -915,28 +948,26 @@ function getProductTimeRanges(projection, request = {}) {
|
|
|
915
948
|
if (bookingEnd > range.end) break;
|
|
916
949
|
const bookingDate = formatDate(cursor);
|
|
917
950
|
if (bookingDate >= dateRange.startDate && bookingDate <= dateRange.endDate) {
|
|
918
|
-
ranges.push(
|
|
919
|
-
key: `${String(product.id)}:${cursor}:${bookingEnd}`,
|
|
920
|
-
productId: product.id,
|
|
921
|
-
source: 'duration_window',
|
|
922
|
-
startAt: formatDateTime(cursor, projection.meta.timezone, fixedOffsetMinutes),
|
|
923
|
-
endAt: formatDateTime(bookingEnd, projection.meta.timezone, fixedOffsetMinutes),
|
|
924
|
-
bookingStartAt: formatDateTime(cursor, projection.meta.timezone, fixedOffsetMinutes),
|
|
925
|
-
bookingEndAt: formatDateTime(bookingEnd, projection.meta.timezone, fixedOffsetMinutes),
|
|
926
|
-
date: formatDate(cursor, projection.meta.timezone),
|
|
927
|
-
startTime: formatTime(cursor, projection.meta.timezone),
|
|
928
|
-
endTime: formatTime(bookingEnd, projection.meta.timezone),
|
|
929
|
-
timezone: projection.meta.timezone,
|
|
930
|
-
scheduleRefs: []
|
|
931
|
-
});
|
|
951
|
+
ranges.push(createDurationTimeRange(product, cursor, durationMinutes, projection, fixedOffsetMinutes));
|
|
932
952
|
}
|
|
933
|
-
cursor = addMinutesZoned(cursor,
|
|
953
|
+
cursor = addMinutesZoned(cursor, slotStepMinutes, projection.meta.timezone);
|
|
934
954
|
}
|
|
935
955
|
});
|
|
956
|
+
if (dateRange.startDate === dateRange.endDate && requestedStartTimes.length > 0) {
|
|
957
|
+
requestedStartTimes.forEach(startTime => {
|
|
958
|
+
const start = toDateTimeInDate(dateRange.startDate, startTime, projection.meta.timezone);
|
|
959
|
+
if (!Number.isFinite(start)) return;
|
|
960
|
+
const end = addMinutesZoned(start, durationMinutes, projection.meta.timezone);
|
|
961
|
+
const startsInOperatingRange = operatingRanges.some(range => range.start <= start && start < range.end);
|
|
962
|
+
if (!startsInOperatingRange) return;
|
|
963
|
+
ranges.push(createDurationTimeRange(product, start, durationMinutes, projection, fixedOffsetMinutes));
|
|
964
|
+
});
|
|
965
|
+
}
|
|
936
966
|
return {
|
|
937
967
|
productId: product.id,
|
|
938
968
|
title: product.title,
|
|
939
969
|
kind: product.kind,
|
|
970
|
+
slotStepMinutes,
|
|
940
971
|
ranges: dedupeProductRanges(ranges)
|
|
941
972
|
};
|
|
942
973
|
});
|
|
@@ -211,6 +211,7 @@ export interface ProductTimeRangeGroup {
|
|
|
211
211
|
productId: AvailabilityId;
|
|
212
212
|
title?: string;
|
|
213
213
|
kind: AvailabilityProductKind;
|
|
214
|
+
slotStepMinutes?: number;
|
|
214
215
|
ranges: ProductTimeRange[];
|
|
215
216
|
}
|
|
216
217
|
export interface AvailabilityAssignment extends AvailabilityAbsoluteRange {
|
|
@@ -231,6 +232,8 @@ export interface GetProductTimeRangesRequest {
|
|
|
231
232
|
dateRange?: Partial<AvailabilityDateRange>;
|
|
232
233
|
resourceIds?: AvailabilityId[];
|
|
233
234
|
partySize?: number;
|
|
235
|
+
durationMinutesByProductId?: Record<string, number>;
|
|
236
|
+
durationStartTimesByProductId?: Record<string, string[]>;
|
|
234
237
|
}
|
|
235
238
|
export interface QueryAvailabilityBaseRequest {
|
|
236
239
|
productIds?: AvailabilityId[];
|
|
@@ -1961,7 +1961,7 @@ class RulesModule extends _BaseModule.BaseModule {
|
|
|
1961
1961
|
// 套餐适用范围配置
|
|
1962
1962
|
const packageScope = usageRules?.package_scope;
|
|
1963
1963
|
const {
|
|
1964
|
-
type: scopeType,
|
|
1964
|
+
type: scopeType = 'product_all',
|
|
1965
1965
|
exclude_bundle_product_ids = [],
|
|
1966
1966
|
include_bundle_product_ids = [],
|
|
1967
1967
|
filter = 0
|
|
@@ -1969,6 +1969,8 @@ class RulesModule extends _BaseModule.BaseModule {
|
|
|
1969
1969
|
const isMainProduct = flatItem.type === 'main'; // 单独购买
|
|
1970
1970
|
const isBundleItem = flatItem.type === 'bundle'; // 套餐中购买
|
|
1971
1971
|
const bundleMainProductId = flatItem.product?.product_id;
|
|
1972
|
+
// 主商品id
|
|
1973
|
+
const mainProductId = flatItem?.originProduct?._productOrigin?.id || flatItem?.parentProduct?.id || 0;
|
|
1972
1974
|
|
|
1973
1975
|
// 主商品直接可用
|
|
1974
1976
|
if (isMainProduct) {
|
|
@@ -1985,7 +1987,7 @@ class RulesModule extends _BaseModule.BaseModule {
|
|
|
1985
1987
|
const priceType = flatItem.bundleItem?.price_type;
|
|
1986
1988
|
const priceTypeExt = flatItem.bundleItem?.price_type_ext;
|
|
1987
1989
|
// 主商品id
|
|
1988
|
-
const mainProductId = flatItem?.originProduct?._productOrigin?.id || flatItem?.parentProduct?.id || 0;
|
|
1990
|
+
// const mainProductId = flatItem?.originProduct?._productOrigin?.id || flatItem?.parentProduct?.id || 0;
|
|
1989
1991
|
// original_price 对应:
|
|
1990
1992
|
// 1. price_type: "markup" && price_type_ext: "product_price"
|
|
1991
1993
|
// markup_price 对应:
|
|
@@ -2010,13 +2012,13 @@ class RulesModule extends _BaseModule.BaseModule {
|
|
|
2010
2012
|
if (!filter) {
|
|
2011
2013
|
isScopeValid = true;
|
|
2012
2014
|
} else {
|
|
2013
|
-
isScopeValid = !exclude_bundle_product_ids.includes(Number(
|
|
2015
|
+
isScopeValid = !exclude_bundle_product_ids.includes(Number(mainProductId));
|
|
2014
2016
|
}
|
|
2015
2017
|
}
|
|
2016
2018
|
|
|
2017
2019
|
// 包含套餐判断, products值兼容旧数据
|
|
2018
2020
|
if (scopeType === 'specific_packages' || scopeType === 'products') {
|
|
2019
|
-
isScopeValid = include_bundle_product_ids.includes(Number(
|
|
2021
|
+
isScopeValid = include_bundle_product_ids.includes(Number(mainProductId));
|
|
2020
2022
|
}
|
|
2021
2023
|
|
|
2022
2024
|
// 价格和套餐适用范围都符合,则可用
|
|
@@ -2078,13 +2080,13 @@ class RulesModule extends _BaseModule.BaseModule {
|
|
|
2078
2080
|
if (!filter) {
|
|
2079
2081
|
isScopeValid = true;
|
|
2080
2082
|
} else {
|
|
2081
|
-
isScopeValid = !exclude_bundle_product_ids.includes(Number(
|
|
2083
|
+
isScopeValid = !exclude_bundle_product_ids.includes(Number(mainProductId));
|
|
2082
2084
|
}
|
|
2083
2085
|
}
|
|
2084
2086
|
|
|
2085
2087
|
// 包含套餐判断, products值兼容旧数据
|
|
2086
2088
|
if (scopeType === 'specific_packages' || scopeType === 'products') {
|
|
2087
|
-
isScopeValid = include_bundle_product_ids.includes(Number(
|
|
2089
|
+
isScopeValid = include_bundle_product_ids.includes(Number(mainProductId));
|
|
2088
2090
|
}
|
|
2089
2091
|
|
|
2090
2092
|
// 价格和套餐适用范围都符合,则可用
|
|
@@ -112,6 +112,8 @@ export interface BaseSalesUpdateOrderProductQuantityParams extends BaseSalesOrde
|
|
|
112
112
|
export interface BaseSalesOrderProduct extends BaseSalesOrderProductIdentity {
|
|
113
113
|
order_detail_id: number | null;
|
|
114
114
|
num: number;
|
|
115
|
+
/** Product 或当前 Variant 的生产编码 */
|
|
116
|
+
production_code?: string;
|
|
115
117
|
product_sku: BaseSalesProductSku;
|
|
116
118
|
/**
|
|
117
119
|
* 券后 **行 composite 单价** = `metadata.main_product_selling_price`
|
|
@@ -3,6 +3,7 @@ import type { ProductData } from '../../../modules/Product/types';
|
|
|
3
3
|
export interface BaseProductDetailOptionItem {
|
|
4
4
|
option_group_item_id?: number | string;
|
|
5
5
|
option_group_id?: number | string;
|
|
6
|
+
production_code?: string;
|
|
6
7
|
num?: number | string;
|
|
7
8
|
quantity?: number | string;
|
|
8
9
|
price?: number | string;
|
|
@@ -10,6 +11,7 @@ export interface BaseProductDetailOptionItem {
|
|
|
10
11
|
[key: string]: any;
|
|
11
12
|
}
|
|
12
13
|
export interface BaseProductDetailBundleItem {
|
|
14
|
+
production_code?: string;
|
|
13
15
|
option?: BaseProductDetailOptionItem[];
|
|
14
16
|
[key: string]: any;
|
|
15
17
|
}
|
|
@@ -18,6 +20,7 @@ export interface BaseProductDetailPayload {
|
|
|
18
20
|
product_id?: number | string | null;
|
|
19
21
|
variant_id?: number | string | null;
|
|
20
22
|
product_variant_id?: number | string | null;
|
|
23
|
+
production_code?: string;
|
|
21
24
|
quantity?: number | string;
|
|
22
25
|
num?: number | string;
|
|
23
26
|
option?: BaseProductDetailOptionItem[];
|
|
@@ -27,6 +27,10 @@ function toPriceString(value, fallback = '0.00') {
|
|
|
27
27
|
if (!Number.isFinite(parsedValue)) return fallback;
|
|
28
28
|
return parsedValue.toFixed(2);
|
|
29
29
|
}
|
|
30
|
+
function normalizeProductionCode(value) {
|
|
31
|
+
if (value === undefined || value === null) return '';
|
|
32
|
+
return String(value).trim();
|
|
33
|
+
}
|
|
30
34
|
function isBlankValue(value) {
|
|
31
35
|
return value === undefined || value === null || typeof value === 'string' && value.trim() === '';
|
|
32
36
|
}
|
|
@@ -108,6 +112,7 @@ function transformBaseProductToOrderProduct(params) {
|
|
|
108
112
|
...(callbackOrigin || {})
|
|
109
113
|
};
|
|
110
114
|
const matchedVariant = findVariantById(callbackOrigin, productVariantId) ?? findVariantById(sourceProduct, productVariantId) ?? findVariantById(origin, productVariantId);
|
|
115
|
+
const productionCode = normalizeProductionCode(Object.prototype.hasOwnProperty.call(payload, 'production_code') ? payload.production_code : productVariantId > 0 ? matchedVariant?.production_code : origin?.production_code ?? sourceProduct?.production_code);
|
|
111
116
|
const hasPriceOverride = payload.price_override !== undefined && payload.price_override !== null && payload.price_override !== '';
|
|
112
117
|
// 手动改价后 payload.price 是分摊后的主商品售价,不能再作为券前 source。
|
|
113
118
|
// 此时优先从商品/variant 快照读取目录价;售价仍由 line_total - bundle 推导。
|
|
@@ -193,6 +198,7 @@ function transformBaseProductToOrderProduct(params) {
|
|
|
193
198
|
return {
|
|
194
199
|
product_id: productId,
|
|
195
200
|
product_variant_id: productVariantId,
|
|
201
|
+
production_code: productionCode,
|
|
196
202
|
unique_identification_number: uniqueIdentificationNumber ? String(uniqueIdentificationNumber) : undefined,
|
|
197
203
|
num: resolvedQuantity,
|
|
198
204
|
product_sku: {
|
|
@@ -257,6 +257,9 @@ function normalizeOrderProduct(product) {
|
|
|
257
257
|
product_id: product.product_id,
|
|
258
258
|
num: getSafeProductNum(product.num),
|
|
259
259
|
product_variant_id: product.product_variant_id,
|
|
260
|
+
...(product.production_code !== undefined && product.production_code !== null ? {
|
|
261
|
+
production_code: String(product.production_code).trim()
|
|
262
|
+
} : {}),
|
|
260
263
|
product_sku: productSku,
|
|
261
264
|
selling_price: composedSellingPrice,
|
|
262
265
|
original_price: finalOriginalPrice,
|
|
@@ -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 | 2 | 1 | 3 | 4 | 5 | 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: "lots_of_space" | "filling_up_fast" | "sold_out";
|
|
349
349
|
}[];
|
|
350
350
|
/**
|
|
351
351
|
* 找到多个资源的公共可用时间段
|
|
@@ -336,6 +336,8 @@ function buildBasePayloadFromCacheItem(cacheItem, ctx) {
|
|
|
336
336
|
id: cacheItem?.id ?? cacheItem?.product_id,
|
|
337
337
|
product_id: resolvedPid,
|
|
338
338
|
variant_id: other?.product_variant_id ?? other?.variant_id ?? 0,
|
|
339
|
+
// SKUOptionsSelection 已按 Product / Variant 解析好主商品编码;显式空串也需保留。
|
|
340
|
+
production_code: other?.production_code ?? cacheItem?.production_code,
|
|
339
341
|
quantity,
|
|
340
342
|
// 规格弹窗本次选择是 option 权威源,避免目录/旧订单里的空 option 覆盖它。
|
|
341
343
|
product_sku: productSku ? {
|
|
@@ -44,6 +44,8 @@ export interface ScanOrderProductSku {
|
|
|
44
44
|
export interface ScanOrderOrderProduct extends ScanOrderOrderProductIdentity {
|
|
45
45
|
order_detail_id: number | null;
|
|
46
46
|
num: number;
|
|
47
|
+
/** Product 或当前 Variant 的生产编码 */
|
|
48
|
+
production_code?: string;
|
|
47
49
|
product_sku: ScanOrderProductSku;
|
|
48
50
|
/**
|
|
49
51
|
* 券后 **行 composite 单价** = `metadata.main_product_selling_price`
|
|
@@ -633,6 +633,9 @@ function normalizeOrderProduct(product) {
|
|
|
633
633
|
product_id: product.product_id,
|
|
634
634
|
num: getSafeProductNum(product.num),
|
|
635
635
|
product_variant_id: product.product_variant_id,
|
|
636
|
+
...(product.production_code !== undefined && product.production_code !== null ? {
|
|
637
|
+
production_code: String(product.production_code).trim()
|
|
638
|
+
} : {}),
|
|
636
639
|
product_sku: productSku,
|
|
637
640
|
selling_price: composedSellingPrice,
|
|
638
641
|
original_price: manualOriginalPrice,
|
|
@@ -58,6 +58,30 @@ function normalizePositiveInteger(value) {
|
|
|
58
58
|
if (!Number.isInteger(normalized) || normalized <= 0) return undefined;
|
|
59
59
|
return normalized;
|
|
60
60
|
}
|
|
61
|
+
function getCandidateDurationMinutes(candidate) {
|
|
62
|
+
const startAt = candidate.bookingStartAt || candidate.startAt;
|
|
63
|
+
const endAt = candidate.bookingEndAt || candidate.endAt;
|
|
64
|
+
try {
|
|
65
|
+
const start = (0, _localClock.localDateTimeToScalar)((0, _localClock.parseLocalDateTime)(startAt));
|
|
66
|
+
const end = (0, _localClock.localDateTimeToScalar)((0, _localClock.parseLocalDateTime)(endAt));
|
|
67
|
+
const minutes = Math.round((end - start) / 60000);
|
|
68
|
+
return Number.isInteger(minutes) && minutes > 0 ? minutes : undefined;
|
|
69
|
+
} catch (_error) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function getCandidateStartTime(candidate) {
|
|
74
|
+
if (/^([01]\d|2[0-3]):[0-5]\d$/.test(candidate.startTime || '')) {
|
|
75
|
+
return candidate.startTime;
|
|
76
|
+
}
|
|
77
|
+
const startAt = candidate.bookingStartAt || candidate.startAt;
|
|
78
|
+
try {
|
|
79
|
+
const start = (0, _localClock.parseLocalDateTime)(startAt);
|
|
80
|
+
return `${String(start.hour).padStart(2, '0')}:${String(start.minute).padStart(2, '0')}`;
|
|
81
|
+
} catch (_error) {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
61
85
|
function isRecord(value) {
|
|
62
86
|
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
63
87
|
}
|
|
@@ -3027,12 +3051,24 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
|
|
|
3027
3051
|
});
|
|
3028
3052
|
}
|
|
3029
3053
|
this.assertAvailabilityCommitWriteCAS(commitWriteGuard);
|
|
3054
|
+
const candidateDurationMinutes = getCandidateDurationMinutes(params.candidate);
|
|
3055
|
+
const candidateStartTime = getCandidateStartTime(params.candidate);
|
|
3030
3056
|
const refreshedRanges = (0, _ResourcePlanner.getProductTimeRanges)(refreshedProjection, {
|
|
3031
3057
|
productIds: [params.candidate.productId],
|
|
3032
3058
|
dateRange: {
|
|
3033
3059
|
startDate: params.candidate.startAt.slice(0, 10),
|
|
3034
3060
|
endDate: params.candidate.startAt.slice(0, 10)
|
|
3035
|
-
}
|
|
3061
|
+
},
|
|
3062
|
+
...(candidateDurationMinutes ? {
|
|
3063
|
+
durationMinutesByProductId: {
|
|
3064
|
+
[String(params.candidate.productId)]: candidateDurationMinutes
|
|
3065
|
+
},
|
|
3066
|
+
...(candidateStartTime ? {
|
|
3067
|
+
durationStartTimesByProductId: {
|
|
3068
|
+
[String(params.candidate.productId)]: [candidateStartTime]
|
|
3069
|
+
}
|
|
3070
|
+
} : {})
|
|
3071
|
+
} : {})
|
|
3036
3072
|
}).flatMap(group => group.ranges);
|
|
3037
3073
|
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);
|
|
3038
3074
|
if (!refreshedCandidateBase) {
|