@pisell/pisellos 0.0.501 → 0.0.503
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/model/strategy/adapter/promotion/index.js +0 -9
- package/dist/modules/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 +653 -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 +218 -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 | 4 | 3 | 2 | 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 buildSubmitPayloadEnhancer;
|
|
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,71 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
414
494
|
throw error;
|
|
415
495
|
}
|
|
416
496
|
}
|
|
497
|
+
// ScanOrder 提交 payload enhancer:
|
|
498
|
+
// - 给所有 booking 注入 appointment_status: 'started'(扫码点餐语义)
|
|
499
|
+
// - 给第一条 booking 补 resources 与 product_uid(仅当存在 resource / rule product)
|
|
500
|
+
// - 追加一条 is_rule=true 的 rule product,与 booking 互相关联
|
|
501
|
+
buildSubmitPayloadEnhancer() {
|
|
502
|
+
const ruleProduct = this.enabledReservationRuleProducts[0];
|
|
503
|
+
const resourceState = this.store.resource;
|
|
504
|
+
return (payload, { bookingUuid, tempOrder }) => {
|
|
505
|
+
var _a;
|
|
506
|
+
const resourceId = tempOrder.resource_id ?? (resourceState == null ? void 0 : resourceState.relationId);
|
|
507
|
+
const pickOriginal = (value) => {
|
|
508
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
509
|
+
const original = value.original;
|
|
510
|
+
return typeof original === "string" && original.length > 0 ? original : void 0;
|
|
511
|
+
}
|
|
512
|
+
return void 0;
|
|
513
|
+
};
|
|
514
|
+
const mainField = pickOriginal(tempOrder.table_number) ?? pickOriginal((_a = resourceState == null ? void 0 : resourceState.table_form_record) == null ? void 0 : _a.name) ?? "";
|
|
515
|
+
const resourceEntry = resourceState && resourceId ? {
|
|
516
|
+
relation_type: "form",
|
|
517
|
+
like_status: "common",
|
|
518
|
+
id: Number(resourceId),
|
|
519
|
+
main_field: mainField,
|
|
520
|
+
form_id: resourceState.tableFormId,
|
|
521
|
+
relation_id: resourceState.relationId ?? resourceId,
|
|
522
|
+
capacity: 1,
|
|
523
|
+
metadata: {}
|
|
524
|
+
} : void 0;
|
|
525
|
+
const ruleProductUid = ruleProduct ? (0, import_utils2.createUuidV4)() : void 0;
|
|
526
|
+
const nextBookings = (payload.bookings || []).map((booking, idx) => ({
|
|
527
|
+
...booking,
|
|
528
|
+
appointment_status: "started",
|
|
529
|
+
...idx === 0 && resourceEntry ? { resources: [resourceEntry] } : {},
|
|
530
|
+
...idx === 0 && ruleProductUid ? { product_uid: ruleProductUid } : {}
|
|
531
|
+
}));
|
|
532
|
+
const nextProducts = [...payload.products || []];
|
|
533
|
+
if (ruleProduct && ruleProductUid) {
|
|
534
|
+
const sellingPrice = String(ruleProduct.price ?? "0.00");
|
|
535
|
+
const originalPrice = String(
|
|
536
|
+
ruleProduct.original_price ?? ruleProduct.price ?? "0.00"
|
|
537
|
+
);
|
|
538
|
+
nextProducts.push({
|
|
539
|
+
product_id: ruleProduct.id,
|
|
540
|
+
product_variant_id: 0,
|
|
541
|
+
num: 1,
|
|
542
|
+
selling_price: sellingPrice,
|
|
543
|
+
original_price: originalPrice,
|
|
544
|
+
payment_price: sellingPrice,
|
|
545
|
+
is_charge_tax: ruleProduct.is_gst ?? 0,
|
|
546
|
+
product_option_item: [],
|
|
547
|
+
discount_list: [],
|
|
548
|
+
product_bundle: [],
|
|
549
|
+
booking_uid: bookingUuid,
|
|
550
|
+
metadata: {
|
|
551
|
+
is_rule: true,
|
|
552
|
+
unique_identification_number: ruleProductUid,
|
|
553
|
+
booking_uid: bookingUuid
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
return { ...payload, bookings: nextBookings, products: nextProducts };
|
|
558
|
+
};
|
|
559
|
+
}
|
|
417
560
|
async submitScanOrder() {
|
|
418
|
-
var _a, _b, _c, _d, _e;
|
|
561
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
419
562
|
this.logMethodStart("submitScanOrder");
|
|
420
563
|
try {
|
|
421
564
|
await this.validateBeforeSubmitByItemRule();
|
|
@@ -426,17 +569,26 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
426
569
|
this.store.entryPaxNumber = pax;
|
|
427
570
|
const tempOrderForSubmit = this.store.order.ensureTempOrder();
|
|
428
571
|
tempOrderForSubmit.metadata = { ...tempOrderForSubmit.metadata, collect_pax: pax };
|
|
572
|
+
tempOrderForSubmit.delivery_type = "shop_service";
|
|
573
|
+
const resourceTableName = (_b = (_a = this.store.resource) == null ? void 0 : _a.table_form_record) == null ? void 0 : _b.name;
|
|
574
|
+
if (resourceTableName && typeof resourceTableName === "object") {
|
|
575
|
+
tempOrderForSubmit.table_number = resourceTableName;
|
|
576
|
+
} else {
|
|
577
|
+
delete tempOrderForSubmit.table_number;
|
|
578
|
+
}
|
|
429
579
|
this.store.order.persistTempOrder();
|
|
580
|
+
const enhancePayload = this.buildSubmitPayloadEnhancer();
|
|
430
581
|
const result = await this.store.order.submitTempOrder({
|
|
431
582
|
cacheId: this.cacheId,
|
|
432
|
-
platform: (
|
|
433
|
-
businessCode: (
|
|
434
|
-
channel: (
|
|
435
|
-
type: (
|
|
583
|
+
platform: (_c = this.otherParams) == null ? void 0 : _c.platform,
|
|
584
|
+
businessCode: (_d = this.otherParams) == null ? void 0 : _d.businessCode,
|
|
585
|
+
channel: (_e = this.otherParams) == null ? void 0 : _e.channel,
|
|
586
|
+
type: (_f = this.otherParams) == null ? void 0 : _f.type,
|
|
587
|
+
enhancePayload
|
|
436
588
|
});
|
|
437
589
|
const tempOrder = this.store.order.getTempOrder();
|
|
438
590
|
this.logMethodSuccess("submitScanOrder", {
|
|
439
|
-
productCount: ((
|
|
591
|
+
productCount: ((_g = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _g.length) || 0
|
|
440
592
|
});
|
|
441
593
|
return result;
|
|
442
594
|
} catch (error) {
|
|
@@ -707,6 +859,7 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
707
859
|
);
|
|
708
860
|
tempOrder.products.push(
|
|
709
861
|
(0, import_utils.normalizeOrderProduct)({
|
|
862
|
+
...sourceItem,
|
|
710
863
|
product_id: productId,
|
|
711
864
|
product_variant_id: productVariantId,
|
|
712
865
|
num: targetQuantity,
|
|
@@ -752,6 +905,7 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
752
905
|
}
|
|
753
906
|
}
|
|
754
907
|
if (hasChanges) {
|
|
908
|
+
this.store.order.applyDiscount();
|
|
755
909
|
await this.store.order.recalculateSummary({ createIfMissing: true });
|
|
756
910
|
this.store.order.persistTempOrder();
|
|
757
911
|
}
|
|
@@ -969,19 +1123,39 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
969
1123
|
const dineInConfig = (openData == null ? void 0 : openData.data) || {};
|
|
970
1124
|
this.otherParams.dineInConfig = dineInConfig;
|
|
971
1125
|
await this.syncItemRuleConfigsFromDineInConfig(dineInConfig);
|
|
972
|
-
const
|
|
1126
|
+
const closedBehaviorValue = dineInConfig == null ? void 0 : dineInConfig["availability.closed_behavior"];
|
|
1127
|
+
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"]);
|
|
1128
|
+
const basicUnavailableMessage = (dineInConfig == null ? void 0 : dineInConfig["basic.unavailable_message"]) || closedMessage;
|
|
1129
|
+
const pauseMessage = (dineInConfig == null ? void 0 : dineInConfig["availability.pause_message"]) || closedMessage;
|
|
1130
|
+
const makeShopClosed = (errorTips, closed_behavior) => ({
|
|
973
1131
|
mode: "shop_closed",
|
|
974
1132
|
order_id: void 0,
|
|
975
1133
|
relation_id: void 0,
|
|
976
1134
|
table_form_id: void 0,
|
|
977
1135
|
deskmate_valid: false,
|
|
978
|
-
errorTips
|
|
1136
|
+
errorTips,
|
|
1137
|
+
closed_behavior
|
|
979
1138
|
});
|
|
1139
|
+
if ((dineInConfig == null ? void 0 : dineInConfig["basic.enable"]) === false) {
|
|
1140
|
+
return makeShopClosed(basicUnavailableMessage);
|
|
1141
|
+
}
|
|
980
1142
|
if ((0, import_utils.toBoolean)(dineInConfig == null ? void 0 : dineInConfig["availability.paused"])) {
|
|
981
1143
|
if ((dineInConfig == null ? void 0 : dineInConfig["availability.pause_behavior"]) === "hide_all") {
|
|
982
|
-
return
|
|
1144
|
+
return makeShopClosed(pauseMessage);
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
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) : [];
|
|
1148
|
+
let outsideOperatingHours = false;
|
|
1149
|
+
if (operatingHourIds.length && this.store.schedule) {
|
|
1150
|
+
const scheduleList = this.store.schedule.getScheduleListByIds(operatingHourIds);
|
|
1151
|
+
if (scheduleList.length) {
|
|
1152
|
+
const now = (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
|
|
1153
|
+
outsideOperatingHours = !(0, import_getDateIsInSchedule.getDateIsInSchedule)(now, scheduleList);
|
|
983
1154
|
}
|
|
984
1155
|
}
|
|
1156
|
+
if (outsideOperatingHours && closedBehaviorValue !== "show_menu_disabled") {
|
|
1157
|
+
return makeShopClosed(closedMessage, closedBehaviorValue);
|
|
1158
|
+
}
|
|
985
1159
|
const config = await this.fetchTableConfigByResourceId(resourceId);
|
|
986
1160
|
const resourceState = this.normalizeResourceState(config, hasOrderId);
|
|
987
1161
|
this.store.resource = resourceState;
|
|
@@ -1000,7 +1174,7 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1000
1174
|
tempOrder.table_form_id = resourceState.tableFormId;
|
|
1001
1175
|
tempOrder.resource_id = resourceId;
|
|
1002
1176
|
const reservationLinkIds = (0, import_utils.collectLinkProductIdsFromReservationRules)(
|
|
1003
|
-
dineInConfig["
|
|
1177
|
+
dineInConfig["fulfillment.enabled_resource_rules"]
|
|
1004
1178
|
);
|
|
1005
1179
|
if (reservationLinkIds.length === 0) {
|
|
1006
1180
|
this.enabledReservationRuleProducts = [];
|
|
@@ -1115,6 +1289,11 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1115
1289
|
submissionIndex: hasOrderId ? 1 : 0,
|
|
1116
1290
|
historicalItems
|
|
1117
1291
|
});
|
|
1292
|
+
if (outsideOperatingHours && closedBehaviorValue === "show_menu_disabled") {
|
|
1293
|
+
availabilityInfo.mode = "submit_disabled";
|
|
1294
|
+
availabilityInfo.errorTips = closedMessage;
|
|
1295
|
+
availabilityInfo.closed_behavior = closedBehaviorValue;
|
|
1296
|
+
}
|
|
1118
1297
|
this.logMethodSuccess("checkResourceAvailable", {
|
|
1119
1298
|
resourceId,
|
|
1120
1299
|
mode: availabilityInfo.mode,
|
|
@@ -1207,6 +1386,35 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1207
1386
|
getEntryPaxNumber() {
|
|
1208
1387
|
return this.store.entryPaxNumber;
|
|
1209
1388
|
}
|
|
1389
|
+
// 读取取餐/送餐开关
|
|
1390
|
+
// 依赖 checkResourceAvailable 已缓存的 dineInConfig
|
|
1391
|
+
getFulfillmentModes() {
|
|
1392
|
+
var _a;
|
|
1393
|
+
this.logMethodStart("getFulfillmentModes");
|
|
1394
|
+
const dineInConfig = ((_a = this.otherParams) == null ? void 0 : _a.dineInConfig) || {};
|
|
1395
|
+
const result = {
|
|
1396
|
+
enablePickup: Boolean(dineInConfig["fulfillment.enable_pickup"]),
|
|
1397
|
+
enableTableService: Boolean(dineInConfig["fulfillment.enable_table_service"])
|
|
1398
|
+
};
|
|
1399
|
+
this.logMethodSuccess("getFulfillmentModes", result);
|
|
1400
|
+
return result;
|
|
1401
|
+
}
|
|
1402
|
+
// 判定后台是否开启客户自定义取餐标识
|
|
1403
|
+
// 依赖 checkResourceAvailable 已缓存的 dineInConfig
|
|
1404
|
+
checkManualPickupRef() {
|
|
1405
|
+
var _a;
|
|
1406
|
+
this.logMethodStart("checkManualPickupRef");
|
|
1407
|
+
const dineInConfig = ((_a = this.otherParams) == null ? void 0 : _a.dineInConfig) || {};
|
|
1408
|
+
const refMode = dineInConfig["fulfillment.fulfillment_ref_mode"];
|
|
1409
|
+
const manualInputType = dineInConfig["fulfillment.manual_input_type"];
|
|
1410
|
+
const enabled = refMode === "manual_input";
|
|
1411
|
+
const result = enabled ? { enabled: true, manualInputType } : { enabled: false };
|
|
1412
|
+
this.logMethodSuccess("checkManualPickupRef", {
|
|
1413
|
+
enabled,
|
|
1414
|
+
manualInputType: enabled ? manualInputType : void 0
|
|
1415
|
+
});
|
|
1416
|
+
return result;
|
|
1417
|
+
}
|
|
1210
1418
|
};
|
|
1211
1419
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1212
1420
|
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>;
|