@pisell/pisellos 0.0.501 → 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/modules/Order/index.d.ts +4 -0
- package/dist/modules/Order/index.js +23 -3
- package/dist/modules/Order/types.d.ts +9 -1
- package/dist/modules/Order/utils.d.ts +8 -1
- package/dist/modules/Order/utils.js +28 -12
- package/dist/solution/BookingByStep/index.d.ts +2 -2
- package/dist/solution/ScanOrder/index.d.ts +15 -0
- package/dist/solution/ScanOrder/index.js +652 -375
- package/dist/solution/ScanOrder/types.d.ts +9 -3
- package/dist/solution/VenueBooking/index.d.ts +28 -5
- package/dist/solution/VenueBooking/index.js +472 -234
- package/dist/solution/VenueBooking/types.d.ts +23 -0
- package/dist/solution/VenueBooking/utils/dateSummary.d.ts +1 -1
- package/dist/solution/VenueBooking/utils/dateSummary.js +1 -1
- 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/promotion/index.js +49 -0
- package/lib/modules/Order/index.d.ts +4 -0
- package/lib/modules/Order/index.js +21 -8
- package/lib/modules/Order/types.d.ts +9 -1
- package/lib/modules/Order/utils.d.ts +8 -1
- package/lib/modules/Order/utils.js +23 -13
- package/lib/solution/BookingByStep/index.d.ts +2 -2
- package/lib/solution/ScanOrder/index.d.ts +15 -0
- package/lib/solution/ScanOrder/index.js +221 -10
- package/lib/solution/ScanOrder/types.d.ts +9 -3
- package/lib/solution/VenueBooking/index.d.ts +28 -5
- package/lib/solution/VenueBooking/index.js +204 -58
- package/lib/solution/VenueBooking/types.d.ts +23 -0
- package/lib/solution/VenueBooking/utils/dateSummary.d.ts +1 -1
- package/lib/solution/VenueBooking/utils/dateSummary.js +1 -1
- 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
|
@@ -172,6 +172,9 @@ function normalizeSubmitProduct(product) {
|
|
|
172
172
|
if (rawMetadata.price_breakdown) {
|
|
173
173
|
cleanMetadata.price_breakdown = rawMetadata.price_breakdown;
|
|
174
174
|
}
|
|
175
|
+
if (rawMetadata.is_rule !== void 0) {
|
|
176
|
+
cleanMetadata.is_rule = rawMetadata.is_rule;
|
|
177
|
+
}
|
|
175
178
|
return {
|
|
176
179
|
...submitProduct,
|
|
177
180
|
...bookingUid ? { booking_uid: bookingUid } : {},
|
|
@@ -286,7 +289,8 @@ function buildSubmitPayload(params) {
|
|
|
286
289
|
platform,
|
|
287
290
|
businessCode,
|
|
288
291
|
channel,
|
|
289
|
-
type
|
|
292
|
+
type,
|
|
293
|
+
enhance
|
|
290
294
|
} = params;
|
|
291
295
|
const scheduleDate = tempOrder.schedule_date || tempOrder.created_at || formatDateTime(now);
|
|
292
296
|
const summary = tempOrder.summary || (0, import_utils.createEmptySummary)();
|
|
@@ -297,8 +301,8 @@ function buildSubmitPayload(params) {
|
|
|
297
301
|
const bookingDuration = resolveTableOccupancyDuration(tempOrder);
|
|
298
302
|
const bookingEnd = bookingStart.add(bookingDuration, "minute");
|
|
299
303
|
const bookings = relationId && tableFormId ? [{
|
|
300
|
-
relation_id:
|
|
301
|
-
form_id:
|
|
304
|
+
relation_id: 0,
|
|
305
|
+
form_id: 0,
|
|
302
306
|
start_time: bookingStart.format("HH:mm"),
|
|
303
307
|
start_date: bookingStart.format("YYYY-MM-DD"),
|
|
304
308
|
end_time: bookingEnd.format("HH:mm"),
|
|
@@ -310,17 +314,17 @@ function buildSubmitPayload(params) {
|
|
|
310
314
|
},
|
|
311
315
|
select_date: bookingStart.format("YYYY-MM-DD"),
|
|
312
316
|
is_all: false,
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
+
like_status: "common",
|
|
318
|
+
schedule_id: 0,
|
|
319
|
+
relation_type: "",
|
|
320
|
+
number: 1
|
|
317
321
|
}] : tempOrder.bookings || [];
|
|
318
322
|
const formRecordIds = relationId && tableFormId ? [{
|
|
319
323
|
form_id: tableFormId,
|
|
320
|
-
|
|
324
|
+
form_record_id: relationId
|
|
321
325
|
}] : void 0;
|
|
322
326
|
const { created_at: _createdAt, summary: _summary, surcharges: _surcharges, ...tempOrderRest } = tempOrder;
|
|
323
|
-
|
|
327
|
+
const payload = {
|
|
324
328
|
...tempOrderRest,
|
|
325
329
|
platform: normalizeSubmitPlatform(platform ?? tempOrder.platform),
|
|
326
330
|
request_unique_idempotency_token: cacheId,
|
|
@@ -348,13 +352,19 @@ function buildSubmitPayload(params) {
|
|
|
348
352
|
contacts_info: tempOrder.contacts_info || [],
|
|
349
353
|
// holder: tempOrder.holder || null,
|
|
350
354
|
// summary,
|
|
351
|
-
metadata: {
|
|
352
|
-
|
|
353
|
-
|
|
355
|
+
metadata: (() => {
|
|
356
|
+
const {
|
|
357
|
+
collect_pax: _collectPax,
|
|
358
|
+
table_occupancy_duration: _tableOccupancyDuration,
|
|
359
|
+
...rest
|
|
360
|
+
} = tempOrder.metadata || {};
|
|
361
|
+
return { ...rest };
|
|
362
|
+
})(),
|
|
354
363
|
products: (tempOrder.products || []).map(
|
|
355
364
|
(product) => normalizeSubmitProduct(product)
|
|
356
365
|
)
|
|
357
366
|
};
|
|
367
|
+
return enhance ? enhance(payload, { tempOrder, bookingUuid, now }) : payload;
|
|
358
368
|
}
|
|
359
369
|
function formatV1Product(products) {
|
|
360
370
|
return products.map((product) => {
|
|
@@ -364,7 +374,7 @@ function formatV1Product(products) {
|
|
|
364
374
|
option: product.product_option_item,
|
|
365
375
|
product_id: product.product_id,
|
|
366
376
|
product_variant_id: product.product_variant_id,
|
|
367
|
-
|
|
377
|
+
num: product.num,
|
|
368
378
|
rowKey: product.product_id,
|
|
369
379
|
session: null,
|
|
370
380
|
unique: createUuidV4()
|
|
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
311
311
|
date: string;
|
|
312
312
|
status: string;
|
|
313
313
|
week: string;
|
|
314
|
-
weekNum: 0 |
|
|
314
|
+
weekNum: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
315
315
|
}[]>;
|
|
316
316
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
317
317
|
private getScheduleDataByIds;
|
|
@@ -330,7 +330,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
330
330
|
count: number;
|
|
331
331
|
left: number;
|
|
332
332
|
summaryCount: number;
|
|
333
|
-
status: "
|
|
333
|
+
status: "lots_of_space" | "filling_up_fast" | "sold_out";
|
|
334
334
|
}[];
|
|
335
335
|
/**
|
|
336
336
|
* 找到多个资源的公共可用时间段
|
|
@@ -52,10 +52,17 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
|
|
|
52
52
|
};
|
|
53
53
|
getTempOrder(): import("./types").ScanOrderTempOrder | null;
|
|
54
54
|
updateTempOrderNote(note: string): string;
|
|
55
|
+
setPickupReferenceMode(mode: 'counter_pickup' | 'table_service'): {
|
|
56
|
+
service_type: 'dine_in';
|
|
57
|
+
pickup_reference_mode: 'counter_pickup' | 'table_service';
|
|
58
|
+
};
|
|
59
|
+
setPickupRef(buzzer: string): string;
|
|
55
60
|
private ensureTempOrder;
|
|
56
61
|
addNewOrder(): Promise<import("./types").ScanOrderTempOrder>;
|
|
62
|
+
restoreOrder(): Promise<import("./types").ScanOrderTempOrder>;
|
|
57
63
|
getOrderProducts(): ScanOrderOrderProduct[];
|
|
58
64
|
getSummary(): Promise<import("./types").ScanOrderSummary>;
|
|
65
|
+
private buildReservationRuleEnhancer;
|
|
59
66
|
submitScanOrder<T = any>(): Promise<T>;
|
|
60
67
|
addProductToOrder(product: Partial<ScanOrderOrderProduct> & ScanOrderOrderProductIdentity): Promise<ScanOrderOrderProduct[]>;
|
|
61
68
|
updateProductInOrder(params: {
|
|
@@ -94,4 +101,12 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
|
|
|
94
101
|
}): Promise<void>;
|
|
95
102
|
setEntryPaxNumber(number: number): Promise<void>;
|
|
96
103
|
getEntryPaxNumber(): number | null;
|
|
104
|
+
getFulfillmentModes(): {
|
|
105
|
+
enablePickup: boolean;
|
|
106
|
+
enableTableService: boolean;
|
|
107
|
+
};
|
|
108
|
+
checkManualPickupRef(): {
|
|
109
|
+
enabled: boolean;
|
|
110
|
+
manualInputType?: string;
|
|
111
|
+
};
|
|
97
112
|
}
|
|
@@ -38,6 +38,8 @@ var import_types = require("./types");
|
|
|
38
38
|
var import_utils = require("./utils");
|
|
39
39
|
var import_types2 = require("../BookingByStep/types");
|
|
40
40
|
var import_ProductList = require("../../modules/ProductList");
|
|
41
|
+
var import_Schedule = require("../../modules/Schedule");
|
|
42
|
+
var import_getDateIsInSchedule = require("../../modules/Schedule/getDateIsInSchedule");
|
|
41
43
|
var import_utils2 = require("../../modules/Order/utils");
|
|
42
44
|
var import_dayjs = __toESM(require("dayjs"));
|
|
43
45
|
var import_itemRule = require("../../model/strategy/adapter/itemRule");
|
|
@@ -226,11 +228,26 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
226
228
|
if (this.store.scanOrderLogger) {
|
|
227
229
|
this.store.scanOrderLogger.setContext(this.getScanOrderLoggerContext());
|
|
228
230
|
}
|
|
231
|
+
const scheduleModule = new import_Schedule.ScheduleModule(`${this.name}_schedule`);
|
|
232
|
+
this.store.schedule = scheduleModule;
|
|
233
|
+
this.core.registerModule(scheduleModule, {
|
|
234
|
+
otherParams: {
|
|
235
|
+
...this.otherParams,
|
|
236
|
+
fatherModule: this.name
|
|
237
|
+
}
|
|
238
|
+
});
|
|
229
239
|
console.log("[ScanOrder] 初始化开始");
|
|
230
240
|
try {
|
|
231
241
|
await ((_e = this.store.order) == null ? void 0 : _e.recalculateSummary({ createIfMissing: false }));
|
|
232
242
|
(_f = this.store.order) == null ? void 0 : _f.persistTempOrder();
|
|
233
243
|
await this.loadRuntimeConfigs();
|
|
244
|
+
if (this.store.schedule) {
|
|
245
|
+
try {
|
|
246
|
+
await this.store.schedule.loadAllSchedule();
|
|
247
|
+
} catch (scheduleError) {
|
|
248
|
+
console.warn("[ScanOrder] loadAllSchedule 失败,operating_hours 判定将跳过", scheduleError);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
234
251
|
await this.refreshItemRuleQuantityLimits();
|
|
235
252
|
this.store.status = "ready";
|
|
236
253
|
console.log("[ScanOrder] 初始化完成");
|
|
@@ -368,6 +385,50 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
368
385
|
throw error;
|
|
369
386
|
}
|
|
370
387
|
}
|
|
388
|
+
// 存储 UI 层选择的取餐方式到 tempOrder.metadata.shop_service_data
|
|
389
|
+
// service_type 在扫码点餐场景固定为 dine_in
|
|
390
|
+
setPickupReferenceMode(mode) {
|
|
391
|
+
this.logMethodStart("setPickupReferenceMode", { mode });
|
|
392
|
+
try {
|
|
393
|
+
if (!this.store.order)
|
|
394
|
+
throw new Error("order 模块未初始化");
|
|
395
|
+
const tempOrder = this.store.order.ensureTempOrder();
|
|
396
|
+
tempOrder.metadata = {
|
|
397
|
+
...tempOrder.metadata || {},
|
|
398
|
+
shop_service_data: {
|
|
399
|
+
...(tempOrder.metadata || {}).shop_service_data || {},
|
|
400
|
+
service_type: "dine_in",
|
|
401
|
+
pickup_reference_mode: mode
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
this.store.order.persistTempOrder();
|
|
405
|
+
this.logMethodSuccess("setPickupReferenceMode", {
|
|
406
|
+
mode
|
|
407
|
+
});
|
|
408
|
+
return tempOrder.metadata.shop_service_data;
|
|
409
|
+
} catch (error) {
|
|
410
|
+
this.logMethodError("setPickupReferenceMode", error, { mode });
|
|
411
|
+
throw error;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
// 存储用户自定义取餐标识到 tempOrder.buzzer
|
|
415
|
+
setPickupRef(buzzer) {
|
|
416
|
+
this.logMethodStart("setPickupRef", {
|
|
417
|
+
buzzerLength: String(buzzer || "").length
|
|
418
|
+
});
|
|
419
|
+
try {
|
|
420
|
+
if (!this.store.order)
|
|
421
|
+
throw new Error("order 模块未初始化");
|
|
422
|
+
const result = this.store.order.updateTempOrderBuzzer(buzzer);
|
|
423
|
+
this.logMethodSuccess("setPickupRef", {
|
|
424
|
+
buzzerLength: result.length
|
|
425
|
+
});
|
|
426
|
+
return result;
|
|
427
|
+
} catch (error) {
|
|
428
|
+
this.logMethodError("setPickupRef", error);
|
|
429
|
+
throw error;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
371
432
|
ensureTempOrder() {
|
|
372
433
|
if (!this.store.order)
|
|
373
434
|
throw new Error("order 模块未初始化");
|
|
@@ -389,6 +450,25 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
389
450
|
throw error;
|
|
390
451
|
}
|
|
391
452
|
}
|
|
453
|
+
// 重置 tempOrder 与与上一单强相关的运行态(resource/entryPaxNumber/enabledReservationRuleProducts),
|
|
454
|
+
// 适用于从支付页通过 react-router 跳回继续下单时清理残留数据
|
|
455
|
+
async restoreOrder() {
|
|
456
|
+
this.logMethodStart("restoreOrder");
|
|
457
|
+
try {
|
|
458
|
+
if (!this.store.order) {
|
|
459
|
+
throw new Error("scanOrder 解决方案需要 order 模块支持");
|
|
460
|
+
}
|
|
461
|
+
this.store.resource = null;
|
|
462
|
+
this.store.entryPaxNumber = 1;
|
|
463
|
+
this.enabledReservationRuleProducts = [];
|
|
464
|
+
const tempOrder = this.store.order.restoreOrder();
|
|
465
|
+
this.logMethodSuccess("restoreOrder");
|
|
466
|
+
return tempOrder;
|
|
467
|
+
} catch (error) {
|
|
468
|
+
this.logMethodError("restoreOrder", error);
|
|
469
|
+
throw error;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
392
472
|
getOrderProducts() {
|
|
393
473
|
this.logMethodStart("getOrderProducts");
|
|
394
474
|
if (!this.store.order)
|
|
@@ -414,8 +494,74 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
414
494
|
throw error;
|
|
415
495
|
}
|
|
416
496
|
}
|
|
497
|
+
// 根据 enabledReservationRuleProducts / store.resource 构造 submit payload enhancer:
|
|
498
|
+
// - 给第一条 booking 补 resources 与 product_uid
|
|
499
|
+
// - 追加一条 is_rule=true 的 rule product,与 booking 互相关联
|
|
500
|
+
// 无 rule product 也无 resource 时返回 undefined,跳过增强
|
|
501
|
+
buildReservationRuleEnhancer() {
|
|
502
|
+
const ruleProduct = this.enabledReservationRuleProducts[0];
|
|
503
|
+
const resourceState = this.store.resource;
|
|
504
|
+
if (!ruleProduct && !resourceState)
|
|
505
|
+
return void 0;
|
|
506
|
+
return (payload, { bookingUuid, tempOrder }) => {
|
|
507
|
+
var _a;
|
|
508
|
+
const resourceId = tempOrder.resource_id ?? (resourceState == null ? void 0 : resourceState.relationId);
|
|
509
|
+
const pickOriginal = (value) => {
|
|
510
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
511
|
+
const original = value.original;
|
|
512
|
+
return typeof original === "string" && original.length > 0 ? original : void 0;
|
|
513
|
+
}
|
|
514
|
+
return void 0;
|
|
515
|
+
};
|
|
516
|
+
const mainField = pickOriginal(tempOrder.table_number) ?? pickOriginal((_a = resourceState == null ? void 0 : resourceState.table_form_record) == null ? void 0 : _a.name) ?? "";
|
|
517
|
+
const resourceEntry = resourceState && resourceId ? {
|
|
518
|
+
relation_type: "form",
|
|
519
|
+
like_status: "common",
|
|
520
|
+
id: Number(resourceId),
|
|
521
|
+
main_field: mainField,
|
|
522
|
+
form_id: resourceState.tableFormId,
|
|
523
|
+
relation_id: resourceState.relationId ?? resourceId,
|
|
524
|
+
capacity: 1,
|
|
525
|
+
metadata: {}
|
|
526
|
+
} : void 0;
|
|
527
|
+
const ruleProductUid = ruleProduct ? (0, import_utils2.createUuidV4)() : void 0;
|
|
528
|
+
const nextBookings = (payload.bookings || []).map(
|
|
529
|
+
(booking, idx) => idx === 0 ? {
|
|
530
|
+
...booking,
|
|
531
|
+
...resourceEntry ? { resources: [resourceEntry] } : {},
|
|
532
|
+
...ruleProductUid ? { product_uid: ruleProductUid } : {}
|
|
533
|
+
} : booking
|
|
534
|
+
);
|
|
535
|
+
const nextProducts = [...payload.products || []];
|
|
536
|
+
if (ruleProduct && ruleProductUid) {
|
|
537
|
+
const sellingPrice = String(ruleProduct.price ?? "0.00");
|
|
538
|
+
const originalPrice = String(
|
|
539
|
+
ruleProduct.original_price ?? ruleProduct.price ?? "0.00"
|
|
540
|
+
);
|
|
541
|
+
nextProducts.push({
|
|
542
|
+
product_id: ruleProduct.id,
|
|
543
|
+
product_variant_id: 0,
|
|
544
|
+
num: 1,
|
|
545
|
+
selling_price: sellingPrice,
|
|
546
|
+
original_price: originalPrice,
|
|
547
|
+
payment_price: sellingPrice,
|
|
548
|
+
is_charge_tax: ruleProduct.is_gst ?? 0,
|
|
549
|
+
product_option_item: [],
|
|
550
|
+
discount_list: [],
|
|
551
|
+
product_bundle: [],
|
|
552
|
+
booking_uid: bookingUuid,
|
|
553
|
+
metadata: {
|
|
554
|
+
is_rule: true,
|
|
555
|
+
unique_identification_number: ruleProductUid,
|
|
556
|
+
booking_uid: bookingUuid
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
return { ...payload, bookings: nextBookings, products: nextProducts };
|
|
561
|
+
};
|
|
562
|
+
}
|
|
417
563
|
async submitScanOrder() {
|
|
418
|
-
var _a, _b, _c, _d, _e;
|
|
564
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
419
565
|
this.logMethodStart("submitScanOrder");
|
|
420
566
|
try {
|
|
421
567
|
await this.validateBeforeSubmitByItemRule();
|
|
@@ -426,17 +572,26 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
426
572
|
this.store.entryPaxNumber = pax;
|
|
427
573
|
const tempOrderForSubmit = this.store.order.ensureTempOrder();
|
|
428
574
|
tempOrderForSubmit.metadata = { ...tempOrderForSubmit.metadata, collect_pax: pax };
|
|
575
|
+
tempOrderForSubmit.delivery_type = "shop_service";
|
|
576
|
+
const resourceTableName = (_b = (_a = this.store.resource) == null ? void 0 : _a.table_form_record) == null ? void 0 : _b.name;
|
|
577
|
+
if (resourceTableName && typeof resourceTableName === "object") {
|
|
578
|
+
tempOrderForSubmit.table_number = resourceTableName;
|
|
579
|
+
} else {
|
|
580
|
+
delete tempOrderForSubmit.table_number;
|
|
581
|
+
}
|
|
429
582
|
this.store.order.persistTempOrder();
|
|
583
|
+
const enhancePayload = this.buildReservationRuleEnhancer();
|
|
430
584
|
const result = await this.store.order.submitTempOrder({
|
|
431
585
|
cacheId: this.cacheId,
|
|
432
|
-
platform: (
|
|
433
|
-
businessCode: (
|
|
434
|
-
channel: (
|
|
435
|
-
type: (
|
|
586
|
+
platform: (_c = this.otherParams) == null ? void 0 : _c.platform,
|
|
587
|
+
businessCode: (_d = this.otherParams) == null ? void 0 : _d.businessCode,
|
|
588
|
+
channel: (_e = this.otherParams) == null ? void 0 : _e.channel,
|
|
589
|
+
type: (_f = this.otherParams) == null ? void 0 : _f.type,
|
|
590
|
+
enhancePayload
|
|
436
591
|
});
|
|
437
592
|
const tempOrder = this.store.order.getTempOrder();
|
|
438
593
|
this.logMethodSuccess("submitScanOrder", {
|
|
439
|
-
productCount: ((
|
|
594
|
+
productCount: ((_g = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _g.length) || 0
|
|
440
595
|
});
|
|
441
596
|
return result;
|
|
442
597
|
} catch (error) {
|
|
@@ -707,6 +862,7 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
707
862
|
);
|
|
708
863
|
tempOrder.products.push(
|
|
709
864
|
(0, import_utils.normalizeOrderProduct)({
|
|
865
|
+
...sourceItem,
|
|
710
866
|
product_id: productId,
|
|
711
867
|
product_variant_id: productVariantId,
|
|
712
868
|
num: targetQuantity,
|
|
@@ -752,6 +908,7 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
752
908
|
}
|
|
753
909
|
}
|
|
754
910
|
if (hasChanges) {
|
|
911
|
+
this.store.order.applyDiscount();
|
|
755
912
|
await this.store.order.recalculateSummary({ createIfMissing: true });
|
|
756
913
|
this.store.order.persistTempOrder();
|
|
757
914
|
}
|
|
@@ -969,19 +1126,39 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
969
1126
|
const dineInConfig = (openData == null ? void 0 : openData.data) || {};
|
|
970
1127
|
this.otherParams.dineInConfig = dineInConfig;
|
|
971
1128
|
await this.syncItemRuleConfigsFromDineInConfig(dineInConfig);
|
|
972
|
-
const
|
|
1129
|
+
const closedBehaviorValue = dineInConfig == null ? void 0 : dineInConfig["availability.closed_behavior"];
|
|
1130
|
+
const closedMessage = (dineInConfig == null ? void 0 : dineInConfig["availability.closed_message"]) || (dineInConfig == null ? void 0 : dineInConfig["availability.message"]) || (dineInConfig == null ? void 0 : dineInConfig["basic.closed_message"]);
|
|
1131
|
+
const basicUnavailableMessage = (dineInConfig == null ? void 0 : dineInConfig["basic.unavailable_message"]) || closedMessage;
|
|
1132
|
+
const pauseMessage = (dineInConfig == null ? void 0 : dineInConfig["availability.pause_message"]) || closedMessage;
|
|
1133
|
+
const makeShopClosed = (errorTips, closed_behavior) => ({
|
|
973
1134
|
mode: "shop_closed",
|
|
974
1135
|
order_id: void 0,
|
|
975
1136
|
relation_id: void 0,
|
|
976
1137
|
table_form_id: void 0,
|
|
977
1138
|
deskmate_valid: false,
|
|
978
|
-
errorTips
|
|
1139
|
+
errorTips,
|
|
1140
|
+
closed_behavior
|
|
979
1141
|
});
|
|
1142
|
+
if ((dineInConfig == null ? void 0 : dineInConfig["basic.enable"]) === false) {
|
|
1143
|
+
return makeShopClosed(basicUnavailableMessage);
|
|
1144
|
+
}
|
|
980
1145
|
if ((0, import_utils.toBoolean)(dineInConfig == null ? void 0 : dineInConfig["availability.paused"])) {
|
|
981
1146
|
if ((dineInConfig == null ? void 0 : dineInConfig["availability.pause_behavior"]) === "hide_all") {
|
|
982
|
-
return
|
|
1147
|
+
return makeShopClosed(pauseMessage);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
const operatingHourIds = Array.isArray(dineInConfig == null ? void 0 : dineInConfig["availability.operating_hours"]) ? dineInConfig["availability.operating_hours"].map((id) => Number(id)).filter((id) => Number.isFinite(id) && id > 0) : [];
|
|
1151
|
+
let outsideOperatingHours = false;
|
|
1152
|
+
if (operatingHourIds.length && this.store.schedule) {
|
|
1153
|
+
const scheduleList = this.store.schedule.getScheduleListByIds(operatingHourIds);
|
|
1154
|
+
if (scheduleList.length) {
|
|
1155
|
+
const now = (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
|
|
1156
|
+
outsideOperatingHours = !(0, import_getDateIsInSchedule.getDateIsInSchedule)(now, scheduleList);
|
|
983
1157
|
}
|
|
984
1158
|
}
|
|
1159
|
+
if (outsideOperatingHours && closedBehaviorValue !== "show_menu_disabled") {
|
|
1160
|
+
return makeShopClosed(closedMessage, closedBehaviorValue);
|
|
1161
|
+
}
|
|
985
1162
|
const config = await this.fetchTableConfigByResourceId(resourceId);
|
|
986
1163
|
const resourceState = this.normalizeResourceState(config, hasOrderId);
|
|
987
1164
|
this.store.resource = resourceState;
|
|
@@ -1000,7 +1177,7 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1000
1177
|
tempOrder.table_form_id = resourceState.tableFormId;
|
|
1001
1178
|
tempOrder.resource_id = resourceId;
|
|
1002
1179
|
const reservationLinkIds = (0, import_utils.collectLinkProductIdsFromReservationRules)(
|
|
1003
|
-
dineInConfig["
|
|
1180
|
+
dineInConfig["fulfillment.enabled_resource_rules"]
|
|
1004
1181
|
);
|
|
1005
1182
|
if (reservationLinkIds.length === 0) {
|
|
1006
1183
|
this.enabledReservationRuleProducts = [];
|
|
@@ -1115,6 +1292,11 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1115
1292
|
submissionIndex: hasOrderId ? 1 : 0,
|
|
1116
1293
|
historicalItems
|
|
1117
1294
|
});
|
|
1295
|
+
if (outsideOperatingHours && closedBehaviorValue === "show_menu_disabled") {
|
|
1296
|
+
availabilityInfo.mode = "submit_disabled";
|
|
1297
|
+
availabilityInfo.errorTips = closedMessage;
|
|
1298
|
+
availabilityInfo.closed_behavior = closedBehaviorValue;
|
|
1299
|
+
}
|
|
1118
1300
|
this.logMethodSuccess("checkResourceAvailable", {
|
|
1119
1301
|
resourceId,
|
|
1120
1302
|
mode: availabilityInfo.mode,
|
|
@@ -1207,6 +1389,35 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1207
1389
|
getEntryPaxNumber() {
|
|
1208
1390
|
return this.store.entryPaxNumber;
|
|
1209
1391
|
}
|
|
1392
|
+
// 读取取餐/送餐开关
|
|
1393
|
+
// 依赖 checkResourceAvailable 已缓存的 dineInConfig
|
|
1394
|
+
getFulfillmentModes() {
|
|
1395
|
+
var _a;
|
|
1396
|
+
this.logMethodStart("getFulfillmentModes");
|
|
1397
|
+
const dineInConfig = ((_a = this.otherParams) == null ? void 0 : _a.dineInConfig) || {};
|
|
1398
|
+
const result = {
|
|
1399
|
+
enablePickup: Boolean(dineInConfig["fulfillment.enable_pickup"]),
|
|
1400
|
+
enableTableService: Boolean(dineInConfig["fulfillment.enable_table_service"])
|
|
1401
|
+
};
|
|
1402
|
+
this.logMethodSuccess("getFulfillmentModes", result);
|
|
1403
|
+
return result;
|
|
1404
|
+
}
|
|
1405
|
+
// 判定后台是否开启客户自定义取餐标识
|
|
1406
|
+
// 依赖 checkResourceAvailable 已缓存的 dineInConfig
|
|
1407
|
+
checkManualPickupRef() {
|
|
1408
|
+
var _a;
|
|
1409
|
+
this.logMethodStart("checkManualPickupRef");
|
|
1410
|
+
const dineInConfig = ((_a = this.otherParams) == null ? void 0 : _a.dineInConfig) || {};
|
|
1411
|
+
const refMode = dineInConfig["fulfillment.fulfillment_ref_mode"];
|
|
1412
|
+
const manualInputType = dineInConfig["fulfillment.manual_input_type"];
|
|
1413
|
+
const enabled = refMode === "manual_input";
|
|
1414
|
+
const result = enabled ? { enabled: true, manualInputType } : { enabled: false };
|
|
1415
|
+
this.logMethodSuccess("checkManualPickupRef", {
|
|
1416
|
+
enabled,
|
|
1417
|
+
manualInputType: enabled ? manualInputType : void 0
|
|
1418
|
+
});
|
|
1419
|
+
return result;
|
|
1420
|
+
}
|
|
1210
1421
|
};
|
|
1211
1422
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1212
1423
|
0 && (module.exports = {
|
|
@@ -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
|
|
@@ -114,6 +114,9 @@ export interface ScanOrderTempOrder {
|
|
|
114
114
|
shop_discount: string;
|
|
115
115
|
surcharge_fee: string;
|
|
116
116
|
note: string;
|
|
117
|
+
buzzer?: string;
|
|
118
|
+
delivery_type?: string;
|
|
119
|
+
table_number?: Record<string, any>;
|
|
117
120
|
schedule_date: string;
|
|
118
121
|
created_at: string;
|
|
119
122
|
products: ScanOrderOrderProduct[];
|
|
@@ -134,11 +137,11 @@ export interface ScanOrderSubmitPayload extends Omit<ScanOrderTempOrder, 'platfo
|
|
|
134
137
|
request_unique_idempotency_token?: string;
|
|
135
138
|
form_record_ids?: Array<{
|
|
136
139
|
form_id: number | string;
|
|
137
|
-
|
|
140
|
+
form_record_id: number | string;
|
|
138
141
|
}>;
|
|
139
142
|
products: ScanOrderSubmitProduct[];
|
|
140
143
|
}
|
|
141
|
-
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';
|
|
142
145
|
export interface ScanOrderTableFormRecord {
|
|
143
146
|
policy?: string | null;
|
|
144
147
|
partyroom_booking?: string | null;
|
|
@@ -151,6 +154,8 @@ export interface ScanOrderAvailabilityInfo {
|
|
|
151
154
|
table_form_id?: string;
|
|
152
155
|
deskmate_valid?: boolean;
|
|
153
156
|
errorTips?: string;
|
|
157
|
+
/** 透传 `availability.closed_behavior`,便于 UI 识别拦截类型(如 show_menu_disabled) */
|
|
158
|
+
closed_behavior?: string;
|
|
154
159
|
/** `/order/dining/table/config` 返回的 `table_form_record` 原样透出 */
|
|
155
160
|
table_form_record?: ScanOrderTableFormRecord | null;
|
|
156
161
|
policy?: string | null;
|
|
@@ -212,6 +217,7 @@ export interface ScanOrderState {
|
|
|
212
217
|
order?: OrderModule;
|
|
213
218
|
salesSummary?: SalesSummaryModule;
|
|
214
219
|
scanOrderLogger?: ScanOrderLoggerModule;
|
|
220
|
+
schedule?: ScheduleModule;
|
|
215
221
|
itemRuleQuantityLimits: QuantityLimitResult[];
|
|
216
222
|
cartValidation: {
|
|
217
223
|
passed: boolean | null;
|
|
@@ -92,25 +92,48 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
|
|
|
92
92
|
/**
|
|
93
93
|
* 切换单个时段的选中状态(选中/取消)。
|
|
94
94
|
* 内部自动处理连续时段的合并与拆分,订单是唯一真相源。
|
|
95
|
+
*
|
|
96
|
+
* slot.productId 指定当前操作针对的是该 resourceId 下的哪一个商品。
|
|
97
|
+
* 同一资源下不同 productId 之间互相隔离,不会相互合并。
|
|
95
98
|
*/
|
|
96
99
|
toggleSlot(slot: VenueSlotSelection): Promise<ScanOrderOrderProduct[]>;
|
|
97
100
|
/**
|
|
98
101
|
* 获取某资源当前选中的所有独立时段(从订单中解析)。
|
|
102
|
+
* 不传 productId 时返回该资源下所有商品的选中时段;传了则精确匹配。
|
|
99
103
|
*/
|
|
100
|
-
getSelectedSlotsForResource(resourceId: number | string): VenueSlotSelection[];
|
|
104
|
+
getSelectedSlotsForResource(resourceId: number | string, productId?: number): VenueSlotSelection[];
|
|
105
|
+
/** getSelectedSlotsForResource 的 (resourceId, productId) 精确版,内部使用。 */
|
|
106
|
+
private getSelectedSlotsForResourceProduct;
|
|
101
107
|
/**
|
|
102
108
|
* 判断某个时段是否已选中。
|
|
109
|
+
* 不传 productId 时:只要该资源下任一商品在 startTime 被选中即返回 true;传了则精确匹配。
|
|
103
110
|
*/
|
|
104
|
-
isSlotSelected(resourceId: number | string, startTime: string): boolean;
|
|
111
|
+
isSlotSelected(resourceId: number | string, startTime: string, productId?: number): boolean;
|
|
105
112
|
/**
|
|
106
|
-
*
|
|
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 判定。
|
|
107
127
|
*/
|
|
108
128
|
getAllSelectedSlots(): Map<number | string, VenueSlotSelection[]>;
|
|
109
129
|
/**
|
|
110
|
-
*
|
|
130
|
+
* 对指定 (resourceId, productId) 的订单商品进行 reconcile:
|
|
111
131
|
* 清除旧商品 → 合并连续时段 → 重新写入。
|
|
132
|
+
* 同一场地下不同商品互不干扰,各自单独 reconcile。
|
|
112
133
|
*/
|
|
113
|
-
private
|
|
134
|
+
private reconcileOrderForResourceProduct;
|
|
135
|
+
/** 给定一个父 rawResource,返回其 combined_resource.resource_ids 对应的子 rawResource 列表。 */
|
|
136
|
+
private getCombinedChildRawResources;
|
|
114
137
|
setSlotConfig(config: Partial<VenueBookingSlotConfig>): void;
|
|
115
138
|
getSlotConfig(): VenueBookingSlotConfig;
|
|
116
139
|
loadSchedules(): Promise<void>;
|