@pisell/pisellos 0.0.500 → 0.0.502
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/model/strategy/adapter/itemRule/adapter.d.ts +8 -0
- package/dist/model/strategy/adapter/itemRule/adapter.js +52 -8
- package/dist/model/strategy/adapter/itemRule/examples.d.ts +15 -0
- package/dist/model/strategy/adapter/itemRule/examples.js +68 -1
- package/dist/model/strategy/adapter/itemRule/index.d.ts +1 -1
- package/dist/model/strategy/adapter/itemRule/index.js +1 -1
- package/dist/model/strategy/adapter/itemRule/type.d.ts +20 -1
- package/dist/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/modules/Order/index.d.ts +10 -0
- package/dist/modules/Order/index.js +64 -40
- package/dist/modules/Order/types.d.ts +13 -1
- package/dist/modules/Order/utils.d.ts +36 -1
- package/dist/modules/Order/utils.js +120 -24
- package/dist/modules/ProductList/index.js +2 -2
- package/dist/modules/Quotation/index.js +6 -3
- package/dist/modules/SalesSummary/types.d.ts +2 -1
- package/dist/modules/SalesSummary/utils.js +10 -10
- package/dist/modules/Schedule/utils.d.ts +1 -1
- package/dist/solution/ScanOrder/index.d.ts +22 -0
- package/dist/solution/ScanOrder/index.js +863 -369
- package/dist/solution/ScanOrder/types.d.ts +31 -8
- package/dist/solution/ScanOrder/utils.d.ts +26 -0
- package/dist/solution/ScanOrder/utils.js +191 -44
- package/dist/solution/VenueBooking/index.d.ts +42 -5
- package/dist/solution/VenueBooking/index.js +692 -280
- package/dist/solution/VenueBooking/types.d.ts +23 -0
- package/dist/solution/VenueBooking/utils/dateSummary.d.ts +2 -1
- package/dist/solution/VenueBooking/utils/dateSummary.js +7 -5
- package/dist/solution/VenueBooking/utils/resource.d.ts +11 -1
- package/dist/solution/VenueBooking/utils/resource.js +57 -21
- package/dist/solution/VenueBooking/utils/slotMerge.d.ts +5 -0
- package/dist/solution/VenueBooking/utils/slotMerge.js +33 -12
- package/dist/solution/VenueBooking/utils/timeSlot.d.ts +1 -1
- package/dist/solution/VenueBooking/utils/timeSlot.js +259 -62
- package/lib/model/strategy/adapter/itemRule/adapter.d.ts +8 -0
- package/lib/model/strategy/adapter/itemRule/adapter.js +41 -2
- package/lib/model/strategy/adapter/itemRule/examples.d.ts +15 -0
- package/lib/model/strategy/adapter/itemRule/examples.js +47 -0
- package/lib/model/strategy/adapter/itemRule/index.d.ts +1 -1
- package/lib/model/strategy/adapter/itemRule/index.js +2 -0
- package/lib/model/strategy/adapter/itemRule/type.d.ts +20 -1
- package/lib/modules/Order/index.d.ts +10 -0
- package/lib/modules/Order/index.js +40 -43
- package/lib/modules/Order/types.d.ts +13 -1
- package/lib/modules/Order/utils.d.ts +36 -1
- package/lib/modules/Order/utils.js +100 -21
- package/lib/modules/ProductList/index.js +3 -2
- package/lib/modules/Quotation/index.js +3 -0
- package/lib/modules/SalesSummary/types.d.ts +2 -1
- package/lib/modules/SalesSummary/utils.js +2 -2
- package/lib/modules/Schedule/utils.d.ts +1 -1
- package/lib/solution/ScanOrder/index.d.ts +22 -0
- package/lib/solution/ScanOrder/index.js +376 -21
- package/lib/solution/ScanOrder/types.d.ts +31 -8
- package/lib/solution/ScanOrder/utils.d.ts +26 -0
- package/lib/solution/ScanOrder/utils.js +128 -19
- package/lib/solution/VenueBooking/index.d.ts +42 -5
- package/lib/solution/VenueBooking/index.js +356 -84
- package/lib/solution/VenueBooking/types.d.ts +23 -0
- package/lib/solution/VenueBooking/utils/dateSummary.d.ts +2 -1
- package/lib/solution/VenueBooking/utils/dateSummary.js +14 -5
- package/lib/solution/VenueBooking/utils/resource.d.ts +11 -1
- package/lib/solution/VenueBooking/utils/resource.js +15 -4
- package/lib/solution/VenueBooking/utils/slotMerge.d.ts +5 -0
- package/lib/solution/VenueBooking/utils/slotMerge.js +29 -12
- package/lib/solution/VenueBooking/utils/timeSlot.d.ts +1 -1
- package/lib/solution/VenueBooking/utils/timeSlot.js +182 -43
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OrderModule, ProductList, SalesSummaryModule, ScanOrderLogInput, ScanOrderLoggerModule, ScanOrderLoggerProviderConfig, ScanOrderLoggerProviderType } from '../../modules';
|
|
1
|
+
import { OrderModule, ProductList, SalesSummaryModule, ScanOrderLogInput, ScanOrderLoggerModule, ScanOrderLoggerProviderConfig, ScanOrderLoggerProviderType, ScheduleModule } from '../../modules';
|
|
2
2
|
import type { QuantityCheckResult, QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
|
|
3
3
|
/**
|
|
4
4
|
* 扫码下单流程 hook
|
|
@@ -36,9 +36,10 @@ export interface ScanOrderOrderProduct extends ScanOrderOrderProductIdentity {
|
|
|
36
36
|
order_detail_id: number | null;
|
|
37
37
|
num: number;
|
|
38
38
|
product_option_item: any[];
|
|
39
|
+
/** 券后单品单价(= 订单域实际成交单价)。未应用券时等同 original_price。 */
|
|
39
40
|
selling_price: string;
|
|
41
|
+
/** 券前单品单价(= 店铺售价),不承载后台划线价语义。 */
|
|
40
42
|
original_price: string;
|
|
41
|
-
payment_price: string;
|
|
42
43
|
tax_fee: string;
|
|
43
44
|
is_charge_tax: number;
|
|
44
45
|
discount_list: any[];
|
|
@@ -47,6 +48,11 @@ export interface ScanOrderOrderProduct extends ScanOrderOrderProductIdentity {
|
|
|
47
48
|
_origin?: Record<string, any>;
|
|
48
49
|
}
|
|
49
50
|
export interface ScanOrderSubmitProduct extends Omit<ScanOrderOrderProduct, '_origin' | 'identity_key'> {
|
|
51
|
+
/**
|
|
52
|
+
* 出站兼容字段:SDK 内部不再消费 payment_price,
|
|
53
|
+
* 仅在提交后端时由 selling_price 派生,保持原有后端契约。
|
|
54
|
+
*/
|
|
55
|
+
payment_price: string;
|
|
50
56
|
}
|
|
51
57
|
export interface ScanOrderSummary {
|
|
52
58
|
product_quantity: number;
|
|
@@ -108,6 +114,9 @@ export interface ScanOrderTempOrder {
|
|
|
108
114
|
shop_discount: string;
|
|
109
115
|
surcharge_fee: string;
|
|
110
116
|
note: string;
|
|
117
|
+
buzzer?: string;
|
|
118
|
+
delivery_type?: string;
|
|
119
|
+
table_number?: Record<string, any>;
|
|
111
120
|
schedule_date: string;
|
|
112
121
|
created_at: string;
|
|
113
122
|
products: ScanOrderOrderProduct[];
|
|
@@ -121,17 +130,23 @@ export interface ScanOrderTempOrder {
|
|
|
121
130
|
holder: Record<string, any> | null;
|
|
122
131
|
summary: ScanOrderSummary;
|
|
123
132
|
metadata: Record<string, any>;
|
|
133
|
+
lastOrderInfo?: Record<string, any>;
|
|
124
134
|
}
|
|
125
135
|
export interface ScanOrderSubmitPayload extends Omit<ScanOrderTempOrder, 'platform' | 'products' | 'created_at' | 'summary' | 'surcharges'> {
|
|
126
136
|
platform: 'H5' | 'PC';
|
|
127
137
|
request_unique_idempotency_token?: string;
|
|
128
138
|
form_record_ids?: Array<{
|
|
129
139
|
form_id: number | string;
|
|
130
|
-
|
|
140
|
+
form_record_id: number | string;
|
|
131
141
|
}>;
|
|
132
142
|
products: ScanOrderSubmitProduct[];
|
|
133
143
|
}
|
|
134
|
-
export type ScanOrderAvailabilityMode = 'idle' | 'shop_closed' | 'resource_block' | 'resource_busy' | 'additional_order_with_code' | 'additional_order';
|
|
144
|
+
export type ScanOrderAvailabilityMode = 'idle' | 'shop_closed' | 'submit_disabled' | 'resource_block' | 'resource_busy' | 'additional_order_with_code' | 'additional_order';
|
|
145
|
+
export interface ScanOrderTableFormRecord {
|
|
146
|
+
policy?: string | null;
|
|
147
|
+
partyroom_booking?: string | null;
|
|
148
|
+
[key: string]: any;
|
|
149
|
+
}
|
|
135
150
|
export interface ScanOrderAvailabilityInfo {
|
|
136
151
|
mode: ScanOrderAvailabilityMode;
|
|
137
152
|
order_id?: string;
|
|
@@ -139,8 +154,18 @@ export interface ScanOrderAvailabilityInfo {
|
|
|
139
154
|
table_form_id?: string;
|
|
140
155
|
deskmate_valid?: boolean;
|
|
141
156
|
errorTips?: string;
|
|
157
|
+
/** 透传 `availability.closed_behavior`,便于 UI 识别拦截类型(如 show_menu_disabled) */
|
|
158
|
+
closed_behavior?: string;
|
|
159
|
+
/** `/order/dining/table/config` 返回的 `table_form_record` 原样透出 */
|
|
160
|
+
table_form_record?: ScanOrderTableFormRecord | null;
|
|
142
161
|
policy?: string | null;
|
|
143
162
|
partyroom_booking?: string | null;
|
|
163
|
+
/** 预约规则关联商品存在 custom 容量时,由 checkResourceAvailable 置为 1 */
|
|
164
|
+
requestEntryPax?: number;
|
|
165
|
+
/** 首个 `capacity.type === 'custom'` 商品里 `custom[0]` 的 min(人数下限) */
|
|
166
|
+
requestPaxMin?: number;
|
|
167
|
+
/** 首个 `capacity.type === 'custom'` 商品里 `custom[0]` 的 max(人数上限) */
|
|
168
|
+
requestPaxMax?: number;
|
|
144
169
|
}
|
|
145
170
|
export interface ScanOrderTableSnackConfig {
|
|
146
171
|
snack?: boolean | number | string;
|
|
@@ -150,9 +175,6 @@ export interface ScanOrderOrderNumberPrefixConfig {
|
|
|
150
175
|
table_order?: string;
|
|
151
176
|
pos?: string;
|
|
152
177
|
}
|
|
153
|
-
export interface ScanOrderTableFormRecord {
|
|
154
|
-
policy?: string | null;
|
|
155
|
-
}
|
|
156
178
|
export interface ScanOrderTableConfigApiData {
|
|
157
179
|
table_max_number?: number | string | null;
|
|
158
180
|
order_count?: number | string | null;
|
|
@@ -183,7 +205,6 @@ export interface ScanOrderResourceState extends ScanOrderAvailabilityInfo {
|
|
|
183
205
|
isFull: boolean;
|
|
184
206
|
orderNumberPrefix: ScanOrderOrderNumberPrefixConfig[];
|
|
185
207
|
raw: ScanOrderTableConfigApiData | null;
|
|
186
|
-
table_form_record?: ScanOrderTableFormRecord | null;
|
|
187
208
|
}
|
|
188
209
|
export interface ScanOrderState {
|
|
189
210
|
entryContext: ScanOrderEntryContext | null;
|
|
@@ -196,11 +217,13 @@ export interface ScanOrderState {
|
|
|
196
217
|
order?: OrderModule;
|
|
197
218
|
salesSummary?: SalesSummaryModule;
|
|
198
219
|
scanOrderLogger?: ScanOrderLoggerModule;
|
|
220
|
+
schedule?: ScheduleModule;
|
|
199
221
|
itemRuleQuantityLimits: QuantityLimitResult[];
|
|
200
222
|
cartValidation: {
|
|
201
223
|
passed: boolean | null;
|
|
202
224
|
failures: QuantityCheckResult[];
|
|
203
225
|
};
|
|
226
|
+
entryPaxNumber: number | null;
|
|
204
227
|
}
|
|
205
228
|
export interface ScanOrderLoggerRuntimeConfig {
|
|
206
229
|
provider?: ScanOrderLoggerProviderType;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderSummary, ScanOrderTempOrder } from './types';
|
|
2
2
|
import type { CartItemSummary, ItemRuleBusinessData, PaxInfo, QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
|
|
3
3
|
import type { StrategyConfig } from '../../model/strategy/type';
|
|
4
|
+
import type { ProductData } from '../../modules/Product/types';
|
|
4
5
|
/**
|
|
5
6
|
* 构建金额全为 0 的空 summary。
|
|
6
7
|
* 作为尚未计算金额时的兜底默认值,避免下游因 undefined 报错。
|
|
@@ -58,8 +59,15 @@ export declare function resolveSkuMatchedQuantityLimits(params: {
|
|
|
58
59
|
export declare function aggregateItemRuleLimit(matchedLimits: QuantityLimitResult[]): {
|
|
59
60
|
min: number | undefined;
|
|
60
61
|
max: number | undefined;
|
|
62
|
+
remainingMax: number | undefined;
|
|
61
63
|
exact: number | undefined;
|
|
62
64
|
mustInclude: boolean;
|
|
65
|
+
validationMessage: string | undefined;
|
|
66
|
+
rawValidationMessage: string | Record<string, string> | undefined;
|
|
67
|
+
maxValidationMessage: string | undefined;
|
|
68
|
+
rawMaxValidationMessage: string | Record<string, string> | undefined;
|
|
69
|
+
minValidationMessage: string | undefined;
|
|
70
|
+
rawMinValidationMessage: string | Record<string, string> | undefined;
|
|
63
71
|
} | null;
|
|
64
72
|
export declare function buildItemRuleBusinessData(params: {
|
|
65
73
|
tempOrder: ScanOrderTempOrder;
|
|
@@ -91,3 +99,21 @@ export declare function getProductIdentityIndex(products: ScanOrderOrderProduct[
|
|
|
91
99
|
* - 保留 _origin 供后续业务流程(如促销规则)使用
|
|
92
100
|
*/
|
|
93
101
|
export declare function normalizeOrderProduct(product: Partial<ScanOrderOrderProduct> & ScanOrderOrderProductIdentity): ScanOrderOrderProduct;
|
|
102
|
+
/**
|
|
103
|
+
* 从 reservation.enabled_reservation_rules 中收集 type=link 的商品 id。
|
|
104
|
+
*/
|
|
105
|
+
export declare function collectLinkProductIdsFromReservationRules(rules: unknown): number[];
|
|
106
|
+
/**
|
|
107
|
+
* 返回列表中第一个带有效 duration.value(分钟)的商品时长。
|
|
108
|
+
*/
|
|
109
|
+
export declare function pickFirstDurationMinutesFromProducts(products: ProductData[]): number | undefined;
|
|
110
|
+
/** 是否存在 capacity.type === 'custom' 的商品 */
|
|
111
|
+
export declare function hasCustomCapacityProduct(products: ProductData[]): boolean;
|
|
112
|
+
/**
|
|
113
|
+
* 在商品列表中找到第一个 `capacity.type === 'custom'` 的商品,取其 `custom` 数组第一项的 min/max。
|
|
114
|
+
* 仅返回有限数字字段;若均无法解析则返回 `undefined`。
|
|
115
|
+
*/
|
|
116
|
+
export declare function pickFirstCustomCapacityPaxBounds(products: ProductData[]): {
|
|
117
|
+
min?: number;
|
|
118
|
+
max?: number;
|
|
119
|
+
} | undefined;
|
|
@@ -170,28 +170,22 @@ export function buildQuantityLimitIndex(limits) {
|
|
|
170
170
|
try {
|
|
171
171
|
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
172
172
|
var limit = _step2.value;
|
|
173
|
-
var
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
productLimitMap.set(productId, [].concat(_toConsumableArray(existed), [limit]));
|
|
190
|
-
}
|
|
191
|
-
} catch (err) {
|
|
192
|
-
_iterator3.e(err);
|
|
193
|
-
} finally {
|
|
194
|
-
_iterator3.f();
|
|
173
|
+
var targets = limit.targets || [];
|
|
174
|
+
// 多目标规则(OR 组)只做购物车聚合校验,不下发到单品维度,
|
|
175
|
+
// 避免 UI 把「组内至少 1 份」误当作每款商品各自的 min,锁死减号按钮。
|
|
176
|
+
if (targets.length !== 1) continue;
|
|
177
|
+
var target = targets[0];
|
|
178
|
+
var productId = Number(target.product_id);
|
|
179
|
+
if (!Number.isFinite(productId) || productId <= 0) continue;
|
|
180
|
+
var variantId = Number(target.product_variant_id);
|
|
181
|
+
var hasVariant = Number.isFinite(variantId) && variantId > 0;
|
|
182
|
+
if (hasVariant) {
|
|
183
|
+
var exactKey = buildProductKey(productId, variantId);
|
|
184
|
+
var existed = exactLimitMap.get(exactKey) || [];
|
|
185
|
+
exactLimitMap.set(exactKey, [].concat(_toConsumableArray(existed), [limit]));
|
|
186
|
+
} else {
|
|
187
|
+
var _existed = productLimitMap.get(productId) || [];
|
|
188
|
+
productLimitMap.set(productId, [].concat(_toConsumableArray(_existed), [limit]));
|
|
195
189
|
}
|
|
196
190
|
}
|
|
197
191
|
} catch (err) {
|
|
@@ -216,38 +210,84 @@ export function aggregateItemRuleLimit(matchedLimits) {
|
|
|
216
210
|
if (!matchedLimits.length) return null;
|
|
217
211
|
var min;
|
|
218
212
|
var max;
|
|
213
|
+
var remainingMax;
|
|
219
214
|
var exact;
|
|
220
215
|
var mustInclude = false;
|
|
221
|
-
|
|
222
|
-
|
|
216
|
+
|
|
217
|
+
// 聚合 validationMessage 按 min / max 两个方向分别输出:
|
|
218
|
+
// - maxValidationMessage:触发"当前 max / remainingMax / exact"的那条规则的文案
|
|
219
|
+
// - minValidationMessage:触发"当前 min / exact"的那条规则的文案
|
|
220
|
+
// 各自再回退到其他带文案的规则(最后回退到第一条非空 validationMessage)。
|
|
221
|
+
// 前端可根据"加号/减号被拦"的方向取对应文案。
|
|
222
|
+
var maxSourceLimit;
|
|
223
|
+
var remainingMaxSourceLimit;
|
|
224
|
+
var exactSourceLimit;
|
|
225
|
+
var minSourceLimit;
|
|
226
|
+
var firstMessagedLimit;
|
|
227
|
+
var _iterator3 = _createForOfIteratorHelper(matchedLimits),
|
|
228
|
+
_step3;
|
|
223
229
|
try {
|
|
224
|
-
for (
|
|
225
|
-
var limit =
|
|
230
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
231
|
+
var limit = _step3.value;
|
|
226
232
|
if (typeof limit.requiredMin === 'number' && Number.isFinite(limit.requiredMin)) {
|
|
227
|
-
|
|
233
|
+
if (min === undefined || limit.requiredMin > min) {
|
|
234
|
+
min = limit.requiredMin;
|
|
235
|
+
minSourceLimit = limit;
|
|
236
|
+
}
|
|
228
237
|
}
|
|
229
238
|
if (typeof limit.requiredMax === 'number' && Number.isFinite(limit.requiredMax)) {
|
|
230
|
-
|
|
239
|
+
if (max === undefined || limit.requiredMax < max) {
|
|
240
|
+
max = limit.requiredMax;
|
|
241
|
+
maxSourceLimit = limit;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (typeof limit.remainingMax === 'number' && Number.isFinite(limit.remainingMax)) {
|
|
245
|
+
if (remainingMax === undefined || limit.remainingMax < remainingMax) {
|
|
246
|
+
remainingMax = limit.remainingMax;
|
|
247
|
+
remainingMaxSourceLimit = limit;
|
|
248
|
+
}
|
|
231
249
|
}
|
|
232
250
|
if (typeof limit.requiredExact === 'number' && Number.isFinite(limit.requiredExact)) {
|
|
233
251
|
exact = limit.requiredExact;
|
|
252
|
+
exactSourceLimit = limit;
|
|
234
253
|
}
|
|
235
254
|
mustInclude = mustInclude || Boolean(limit.mustInclude);
|
|
255
|
+
if (!firstMessagedLimit && limit.validationMessage) {
|
|
256
|
+
firstMessagedLimit = limit;
|
|
257
|
+
}
|
|
236
258
|
}
|
|
237
259
|
} catch (err) {
|
|
238
|
-
|
|
260
|
+
_iterator3.e(err);
|
|
239
261
|
} finally {
|
|
240
|
-
|
|
262
|
+
_iterator3.f();
|
|
241
263
|
}
|
|
242
264
|
if (typeof exact === 'number' && Number.isFinite(exact)) {
|
|
243
265
|
min = exact;
|
|
244
266
|
max = exact;
|
|
245
267
|
}
|
|
268
|
+
var maxMessageSource = maxSourceLimit || remainingMaxSourceLimit || exactSourceLimit || firstMessagedLimit;
|
|
269
|
+
var minMessageSource = minSourceLimit || exactSourceLimit || firstMessagedLimit;
|
|
270
|
+
var maxValidationMessage = maxMessageSource === null || maxMessageSource === void 0 ? void 0 : maxMessageSource.validationMessage;
|
|
271
|
+
var rawMaxValidationMessage = maxMessageSource === null || maxMessageSource === void 0 ? void 0 : maxMessageSource.rawValidationMessage;
|
|
272
|
+
var minValidationMessage = minMessageSource === null || minMessageSource === void 0 ? void 0 : minMessageSource.validationMessage;
|
|
273
|
+
var rawMinValidationMessage = minMessageSource === null || minMessageSource === void 0 ? void 0 : minMessageSource.rawValidationMessage;
|
|
274
|
+
|
|
275
|
+
// validationMessage / rawValidationMessage 保留为"最严格限制"的聚合文案,
|
|
276
|
+
// 便于旧消费者(只关心 max 侧)不破坏。优先 max → min。
|
|
277
|
+
var validationMessage = maxValidationMessage !== null && maxValidationMessage !== void 0 ? maxValidationMessage : minValidationMessage;
|
|
278
|
+
var rawValidationMessage = rawMaxValidationMessage !== null && rawMaxValidationMessage !== void 0 ? rawMaxValidationMessage : rawMinValidationMessage;
|
|
246
279
|
return {
|
|
247
280
|
min: min,
|
|
248
281
|
max: max,
|
|
282
|
+
remainingMax: remainingMax,
|
|
249
283
|
exact: exact,
|
|
250
|
-
mustInclude: mustInclude
|
|
284
|
+
mustInclude: mustInclude,
|
|
285
|
+
validationMessage: validationMessage,
|
|
286
|
+
rawValidationMessage: rawValidationMessage,
|
|
287
|
+
maxValidationMessage: maxValidationMessage,
|
|
288
|
+
rawMaxValidationMessage: rawMaxValidationMessage,
|
|
289
|
+
minValidationMessage: minValidationMessage,
|
|
290
|
+
rawMinValidationMessage: rawMinValidationMessage
|
|
251
291
|
};
|
|
252
292
|
}
|
|
253
293
|
export function buildItemRuleBusinessData(params) {
|
|
@@ -295,11 +335,11 @@ export function buildItemRuleBusinessData(params) {
|
|
|
295
335
|
export function attachItemRuleLimitsToTopLevelProducts(productList, limits) {
|
|
296
336
|
if (!Array.isArray(productList)) return productList;
|
|
297
337
|
var limitIndex = buildQuantityLimitIndex(limits || []);
|
|
298
|
-
var
|
|
299
|
-
|
|
338
|
+
var _iterator4 = _createForOfIteratorHelper(productList),
|
|
339
|
+
_step4;
|
|
300
340
|
try {
|
|
301
|
-
for (
|
|
302
|
-
var item =
|
|
341
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
342
|
+
var item = _step4.value;
|
|
303
343
|
if (!item || _typeof(item) !== 'object') continue;
|
|
304
344
|
var productItem = item;
|
|
305
345
|
var productId = getTopLevelProductId(productItem);
|
|
@@ -318,9 +358,9 @@ export function attachItemRuleLimitsToTopLevelProducts(productList, limits) {
|
|
|
318
358
|
}
|
|
319
359
|
}
|
|
320
360
|
} catch (err) {
|
|
321
|
-
|
|
361
|
+
_iterator4.e(err);
|
|
322
362
|
} finally {
|
|
323
|
-
|
|
363
|
+
_iterator4.f();
|
|
324
364
|
}
|
|
325
365
|
return productList;
|
|
326
366
|
}
|
|
@@ -358,8 +398,14 @@ export function normalizeOrderProduct(product) {
|
|
|
358
398
|
if (product.identity_key && !metadata.unique_identification_number) {
|
|
359
399
|
metadata.unique_identification_number = product.identity_key;
|
|
360
400
|
}
|
|
361
|
-
|
|
401
|
+
|
|
402
|
+
// selling_price:券后成交单价;original_price:券前店铺售价。
|
|
403
|
+
// 初次加购时两者相等(入口层应保证 caller 传的 original_price == selling_price);
|
|
404
|
+
// 券应用后由 Rules 引擎只改动 selling_price,保留 original_price 以便还原 / 展示划线对比。
|
|
405
|
+
// 注意:这里 caller 若显式传入了 original_price(例如 Rules 回写或单测场景),要尊重该值,
|
|
406
|
+
// 让券后状态能正确通过再次 normalize。
|
|
362
407
|
var resolvedSellingPrice = product.selling_price || '0.00';
|
|
408
|
+
var resolvedOriginalPrice = product.original_price || resolvedSellingPrice;
|
|
363
409
|
if (metadata.main_product_original_price === undefined) {
|
|
364
410
|
metadata.main_product_original_price = resolvedOriginalPrice;
|
|
365
411
|
}
|
|
@@ -367,14 +413,14 @@ export function normalizeOrderProduct(product) {
|
|
|
367
413
|
metadata.main_product_selling_price = resolvedSellingPrice;
|
|
368
414
|
}
|
|
369
415
|
if (metadata.source_product_price === undefined) {
|
|
370
|
-
var _product$_origin$
|
|
371
|
-
metadata.source_product_price = (_product$_origin$
|
|
416
|
+
var _ref, _product$_origin$pric, _product$_origin, _product$_origin2;
|
|
417
|
+
metadata.source_product_price = (_ref = (_product$_origin$pric = (_product$_origin = product._origin) === null || _product$_origin === void 0 ? void 0 : _product$_origin.price) !== null && _product$_origin$pric !== void 0 ? _product$_origin$pric : (_product$_origin2 = product._origin) === null || _product$_origin2 === void 0 ? void 0 : _product$_origin2.base_price) !== null && _ref !== void 0 ? _ref : resolvedSellingPrice;
|
|
372
418
|
}
|
|
373
419
|
var normalizedBundle = (product.product_bundle || []).map(function (item) {
|
|
374
|
-
var
|
|
420
|
+
var _ref2, _item$bundle_selling_, _ref3, _ref4, _item$custom_price;
|
|
375
421
|
return _objectSpread(_objectSpread({}, item), {}, {
|
|
376
|
-
bundle_selling_price: (
|
|
377
|
-
custom_price: (
|
|
422
|
+
bundle_selling_price: (_ref2 = (_item$bundle_selling_ = item.bundle_selling_price) !== null && _item$bundle_selling_ !== void 0 ? _item$bundle_selling_ : item.price) !== null && _ref2 !== void 0 ? _ref2 : '0.00',
|
|
423
|
+
custom_price: (_ref3 = (_ref4 = (_item$custom_price = item.custom_price) !== null && _item$custom_price !== void 0 ? _item$custom_price : item.bundle_selling_price) !== null && _ref4 !== void 0 ? _ref4 : item.price) !== null && _ref3 !== void 0 ? _ref3 : '0.00'
|
|
378
424
|
});
|
|
379
425
|
});
|
|
380
426
|
return {
|
|
@@ -386,7 +432,6 @@ export function normalizeOrderProduct(product) {
|
|
|
386
432
|
product_option_item: product.product_option_item || [],
|
|
387
433
|
selling_price: resolvedSellingPrice,
|
|
388
434
|
original_price: resolvedOriginalPrice,
|
|
389
|
-
payment_price: product.payment_price || '0.00',
|
|
390
435
|
tax_fee: product.tax_fee || '0.00',
|
|
391
436
|
is_charge_tax: (_product$is_charge_ta = product.is_charge_tax) !== null && _product$is_charge_ta !== void 0 ? _product$is_charge_ta : 0,
|
|
392
437
|
discount_list: product.discount_list || [],
|
|
@@ -394,4 +439,106 @@ export function normalizeOrderProduct(product) {
|
|
|
394
439
|
metadata: metadata,
|
|
395
440
|
_origin: product._origin
|
|
396
441
|
};
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* 从 reservation.enabled_reservation_rules 中收集 type=link 的商品 id。
|
|
446
|
+
*/
|
|
447
|
+
export function collectLinkProductIdsFromReservationRules(rules) {
|
|
448
|
+
if (!Array.isArray(rules)) return [];
|
|
449
|
+
var ids = [];
|
|
450
|
+
var _iterator5 = _createForOfIteratorHelper(rules),
|
|
451
|
+
_step5;
|
|
452
|
+
try {
|
|
453
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
454
|
+
var entry = _step5.value;
|
|
455
|
+
if (!entry || _typeof(entry) !== 'object') continue;
|
|
456
|
+
var rec = entry;
|
|
457
|
+
if (rec.type !== 'link') continue;
|
|
458
|
+
if (!Array.isArray(rec.value)) continue;
|
|
459
|
+
var _iterator6 = _createForOfIteratorHelper(rec.value),
|
|
460
|
+
_step6;
|
|
461
|
+
try {
|
|
462
|
+
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
463
|
+
var v = _step6.value;
|
|
464
|
+
var n = Number(v);
|
|
465
|
+
if (Number.isFinite(n) && n > 0) ids.push(Math.floor(n));
|
|
466
|
+
}
|
|
467
|
+
} catch (err) {
|
|
468
|
+
_iterator6.e(err);
|
|
469
|
+
} finally {
|
|
470
|
+
_iterator6.f();
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
} catch (err) {
|
|
474
|
+
_iterator5.e(err);
|
|
475
|
+
} finally {
|
|
476
|
+
_iterator5.f();
|
|
477
|
+
}
|
|
478
|
+
return _toConsumableArray(new Set(ids));
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* 返回列表中第一个带有效 duration.value(分钟)的商品时长。
|
|
483
|
+
*/
|
|
484
|
+
export function pickFirstDurationMinutesFromProducts(products) {
|
|
485
|
+
var _iterator7 = _createForOfIteratorHelper(products),
|
|
486
|
+
_step7;
|
|
487
|
+
try {
|
|
488
|
+
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
|
489
|
+
var _product$duration;
|
|
490
|
+
var product = _step7.value;
|
|
491
|
+
var value = product === null || product === void 0 || (_product$duration = product.duration) === null || _product$duration === void 0 ? void 0 : _product$duration.value;
|
|
492
|
+
var n = Number(value);
|
|
493
|
+
if (Number.isFinite(n) && n > 0) return Math.floor(n);
|
|
494
|
+
}
|
|
495
|
+
} catch (err) {
|
|
496
|
+
_iterator7.e(err);
|
|
497
|
+
} finally {
|
|
498
|
+
_iterator7.f();
|
|
499
|
+
}
|
|
500
|
+
return undefined;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/** 是否存在 capacity.type === 'custom' 的商品 */
|
|
504
|
+
export function hasCustomCapacityProduct(products) {
|
|
505
|
+
return products.some(function (p) {
|
|
506
|
+
var _p$capacity;
|
|
507
|
+
return (p === null || p === void 0 || (_p$capacity = p.capacity) === null || _p$capacity === void 0 ? void 0 : _p$capacity.type) === 'custom';
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* 在商品列表中找到第一个 `capacity.type === 'custom'` 的商品,取其 `custom` 数组第一项的 min/max。
|
|
513
|
+
* 仅返回有限数字字段;若均无法解析则返回 `undefined`。
|
|
514
|
+
*/
|
|
515
|
+
export function pickFirstCustomCapacityPaxBounds(products) {
|
|
516
|
+
var _iterator8 = _createForOfIteratorHelper(products),
|
|
517
|
+
_step8;
|
|
518
|
+
try {
|
|
519
|
+
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
|
|
520
|
+
var p = _step8.value;
|
|
521
|
+
var cap = p === null || p === void 0 ? void 0 : p.capacity;
|
|
522
|
+
if (!cap || cap.type !== 'custom') continue;
|
|
523
|
+
if (!Array.isArray(cap.custom) || cap.custom.length === 0) continue;
|
|
524
|
+
var row = cap.custom[0];
|
|
525
|
+
if (!row || _typeof(row) !== 'object') continue;
|
|
526
|
+
var raw = row;
|
|
527
|
+
var out = {};
|
|
528
|
+
if (raw.min !== null && raw.min !== undefined && raw.min !== '') {
|
|
529
|
+
var min = Number(raw.min);
|
|
530
|
+
if (Number.isFinite(min)) out.min = min;
|
|
531
|
+
}
|
|
532
|
+
if (raw.max !== null && raw.max !== undefined && raw.max !== '') {
|
|
533
|
+
var max = Number(raw.max);
|
|
534
|
+
if (Number.isFinite(max)) out.max = max;
|
|
535
|
+
}
|
|
536
|
+
if (out.min !== undefined || out.max !== undefined) return out;
|
|
537
|
+
}
|
|
538
|
+
} catch (err) {
|
|
539
|
+
_iterator8.e(err);
|
|
540
|
+
} finally {
|
|
541
|
+
_iterator8.f();
|
|
542
|
+
}
|
|
543
|
+
return undefined;
|
|
397
544
|
}
|
|
@@ -25,6 +25,7 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
|
|
|
25
25
|
private cacheId;
|
|
26
26
|
private window;
|
|
27
27
|
private request;
|
|
28
|
+
private baseSlotConfig;
|
|
28
29
|
private itemRuleEvaluator;
|
|
29
30
|
private itemRuleConfigs;
|
|
30
31
|
private itemRuleConfigsPromise;
|
|
@@ -80,6 +81,9 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
|
|
|
80
81
|
startDate: string;
|
|
81
82
|
endDate: string;
|
|
82
83
|
}): Promise<void>;
|
|
84
|
+
private getOperatingHoursScheduleIds;
|
|
85
|
+
private resolveSlotConfigForDate;
|
|
86
|
+
private syncOperatingHoursToSlotConfig;
|
|
83
87
|
getDateRangeSummary(params: {
|
|
84
88
|
startDate: string;
|
|
85
89
|
endDate: string;
|
|
@@ -88,25 +92,48 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
|
|
|
88
92
|
/**
|
|
89
93
|
* 切换单个时段的选中状态(选中/取消)。
|
|
90
94
|
* 内部自动处理连续时段的合并与拆分,订单是唯一真相源。
|
|
95
|
+
*
|
|
96
|
+
* slot.productId 指定当前操作针对的是该 resourceId 下的哪一个商品。
|
|
97
|
+
* 同一资源下不同 productId 之间互相隔离,不会相互合并。
|
|
91
98
|
*/
|
|
92
99
|
toggleSlot(slot: VenueSlotSelection): Promise<ScanOrderOrderProduct[]>;
|
|
93
100
|
/**
|
|
94
101
|
* 获取某资源当前选中的所有独立时段(从订单中解析)。
|
|
102
|
+
* 不传 productId 时返回该资源下所有商品的选中时段;传了则精确匹配。
|
|
95
103
|
*/
|
|
96
|
-
getSelectedSlotsForResource(resourceId: number | string): VenueSlotSelection[];
|
|
104
|
+
getSelectedSlotsForResource(resourceId: number | string, productId?: number): VenueSlotSelection[];
|
|
105
|
+
/** getSelectedSlotsForResource 的 (resourceId, productId) 精确版,内部使用。 */
|
|
106
|
+
private getSelectedSlotsForResourceProduct;
|
|
97
107
|
/**
|
|
98
108
|
* 判断某个时段是否已选中。
|
|
109
|
+
* 不传 productId 时:只要该资源下任一商品在 startTime 被选中即返回 true;传了则精确匹配。
|
|
99
110
|
*/
|
|
100
|
-
isSlotSelected(resourceId: number | string, startTime: string): boolean;
|
|
111
|
+
isSlotSelected(resourceId: number | string, startTime: string, productId?: number): boolean;
|
|
101
112
|
/**
|
|
102
|
-
*
|
|
113
|
+
* 判断指定 (resourceId, productId, startTime) 格子是否应因其它已选项而被禁用。
|
|
114
|
+
* 规则:
|
|
115
|
+
* 1) 同一 resourceId 下若已选了另一个 productId 的同 startTime → 禁用
|
|
116
|
+
* 2) 当前 resource 是组合资源:若其任一 child resource 在 startTime 被选中 → 禁用
|
|
117
|
+
* 3) 当前 resource 是某些组合资源的 child:若该组合资源在 startTime 被选中 → 禁用
|
|
118
|
+
* 4) 两个组合资源的 child 集合有交集,且对方在该 startTime 被选中 → 禁用
|
|
119
|
+
*/
|
|
120
|
+
isSlotDisabledBySelection(params: {
|
|
121
|
+
resourceId: number | string;
|
|
122
|
+
productId: number;
|
|
123
|
+
startTime: string;
|
|
124
|
+
}): boolean;
|
|
125
|
+
/**
|
|
126
|
+
* 获取所有已选时段(按资源分组)。每个 slot 上带 productId,便于 UI 做 per-product 判定。
|
|
103
127
|
*/
|
|
104
128
|
getAllSelectedSlots(): Map<number | string, VenueSlotSelection[]>;
|
|
105
129
|
/**
|
|
106
|
-
*
|
|
130
|
+
* 对指定 (resourceId, productId) 的订单商品进行 reconcile:
|
|
107
131
|
* 清除旧商品 → 合并连续时段 → 重新写入。
|
|
132
|
+
* 同一场地下不同商品互不干扰,各自单独 reconcile。
|
|
108
133
|
*/
|
|
109
|
-
private
|
|
134
|
+
private reconcileOrderForResourceProduct;
|
|
135
|
+
/** 给定一个父 rawResource,返回其 combined_resource.resource_ids 对应的子 rawResource 列表。 */
|
|
136
|
+
private getCombinedChildRawResources;
|
|
110
137
|
setSlotConfig(config: Partial<VenueBookingSlotConfig>): void;
|
|
111
138
|
getSlotConfig(): VenueBookingSlotConfig;
|
|
112
139
|
loadSchedules(): Promise<void>;
|
|
@@ -159,5 +186,15 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
|
|
|
159
186
|
private refreshCartValidationPassed;
|
|
160
187
|
setItemRuleRuntimeConfig(config?: VenueBookingItemRuleRuntimeConfig): Promise<void>;
|
|
161
188
|
getOtherParams(): Record<string, any>;
|
|
189
|
+
private static readonly UI_STATE_KEY_PREFIX;
|
|
190
|
+
private getUIStateBucketKey;
|
|
191
|
+
private readUIStateBucket;
|
|
192
|
+
private writeUIStateBucket;
|
|
193
|
+
setUIState(key: string, value: any): void;
|
|
194
|
+
getUIState<T = any>(key: string): T | undefined;
|
|
195
|
+
deleteUIState(key: string): void;
|
|
162
196
|
checkOpenDataAvailability(): Promise<OpenDataAvailabilityResult>;
|
|
197
|
+
setOtherParams(params: Record<string, any>, { cover }?: {
|
|
198
|
+
cover?: boolean;
|
|
199
|
+
}): Promise<void>;
|
|
163
200
|
}
|