@pisell/pisellos 2.1.128 → 2.1.130

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.
Files changed (46) hide show
  1. package/dist/model/strategy/adapter/promotion/index.js +0 -9
  2. package/dist/modules/Order/index.d.ts +4 -0
  3. package/dist/modules/Order/index.js +18 -1
  4. package/dist/modules/Order/types.d.ts +9 -1
  5. package/dist/modules/Order/utils.d.ts +7 -0
  6. package/dist/modules/Order/utils.js +27 -11
  7. package/dist/solution/ScanOrder/index.d.ts +27 -3
  8. package/dist/solution/ScanOrder/index.js +865 -481
  9. package/dist/solution/ScanOrder/types.d.ts +34 -24
  10. package/dist/solution/ScanOrder/types.js +5 -1
  11. package/dist/solution/ScanOrder/utils.d.ts +13 -1
  12. package/dist/solution/ScanOrder/utils.js +45 -6
  13. package/dist/solution/VenueBooking/index.d.ts +28 -5
  14. package/dist/solution/VenueBooking/index.js +463 -227
  15. package/dist/solution/VenueBooking/types.d.ts +23 -0
  16. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +1 -1
  17. package/dist/solution/VenueBooking/utils/dateSummary.js +1 -1
  18. package/dist/solution/VenueBooking/utils/resource.d.ts +11 -1
  19. package/dist/solution/VenueBooking/utils/resource.js +57 -21
  20. package/dist/solution/VenueBooking/utils/slotMerge.d.ts +5 -0
  21. package/dist/solution/VenueBooking/utils/slotMerge.js +33 -12
  22. package/dist/solution/VenueBooking/utils/timeSlot.d.ts +1 -1
  23. package/dist/solution/VenueBooking/utils/timeSlot.js +259 -62
  24. package/lib/model/strategy/adapter/promotion/index.js +49 -0
  25. package/lib/modules/Order/index.d.ts +4 -0
  26. package/lib/modules/Order/index.js +14 -1
  27. package/lib/modules/Order/types.d.ts +9 -1
  28. package/lib/modules/Order/utils.d.ts +7 -0
  29. package/lib/modules/Order/utils.js +22 -12
  30. package/lib/solution/ScanOrder/index.d.ts +27 -3
  31. package/lib/solution/ScanOrder/index.js +409 -114
  32. package/lib/solution/ScanOrder/types.d.ts +34 -24
  33. package/lib/solution/ScanOrder/utils.d.ts +13 -1
  34. package/lib/solution/ScanOrder/utils.js +37 -0
  35. package/lib/solution/VenueBooking/index.d.ts +28 -5
  36. package/lib/solution/VenueBooking/index.js +203 -58
  37. package/lib/solution/VenueBooking/types.d.ts +23 -0
  38. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +1 -1
  39. package/lib/solution/VenueBooking/utils/dateSummary.js +1 -1
  40. package/lib/solution/VenueBooking/utils/resource.d.ts +11 -1
  41. package/lib/solution/VenueBooking/utils/resource.js +15 -4
  42. package/lib/solution/VenueBooking/utils/slotMerge.d.ts +5 -0
  43. package/lib/solution/VenueBooking/utils/slotMerge.js +29 -12
  44. package/lib/solution/VenueBooking/utils/timeSlot.d.ts +1 -1
  45. package/lib/solution/VenueBooking/utils/timeSlot.js +182 -43
  46. package/package.json +1 -1
@@ -38,11 +38,13 @@ 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");
44
46
  __reExport(ScanOrder_exports, require("./types"), module.exports);
45
- var ScanOrderImpl = class extends import_BaseModule.BaseModule {
47
+ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
46
48
  constructor(name, version) {
47
49
  super(name, version);
48
50
  this.defaultName = "scanOrder";
@@ -82,11 +84,11 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
82
84
  }
83
85
  serializeError(error) {
84
86
  if (error instanceof Error) {
85
- return {
87
+ return JSON.stringify({
86
88
  name: error.name,
87
89
  message: error.message,
88
90
  stack: error.stack
89
- };
91
+ });
90
92
  }
91
93
  return {
92
94
  message: String(error)
@@ -202,7 +204,7 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
202
204
  const loggerProvider = ((_c2 = this.otherParams) == null ? void 0 : _c2.scanOrderLoggerProvider) || "feishu";
203
205
  const loggerConfig = ((_d2 = this.otherParams) == null ? void 0 : _d2.scanOrderLoggerConfig) || {
204
206
  feishu: {
205
- // webhook: 'https://open.feishu.cn/open-apis/bot/v2/hook/216b3fe6-af98-424e-8706-f0471241a7ed',
207
+ webhook: "https://open.feishu.cn/open-apis/bot/v2/hook/216b3fe6-af98-424e-8706-f0471241a7ed"
206
208
  }
207
209
  };
208
210
  this.core.registerModule(targetModule, {
@@ -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,90 @@ 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 的 metadata 注入 resource_select_type(来自预约规则商品的 resource.type)
500
+ // - 给第一条 booking 补 resources 与 product_uid(仅当存在 resource / rule product)
501
+ // - 追加一条 is_rule=true 的 rule product,与 booking 互相关联
502
+ buildSubmitPayloadEnhancer() {
503
+ const ruleProduct = this.enabledReservationRuleProducts[0];
504
+ const resourceState = this.store.resource;
505
+ const resourceSelectType = resourceState == null ? void 0 : resourceState.resourceSelectType;
506
+ const resolveResourceCapacity = () => {
507
+ var _a;
508
+ if (resourceSelectType === "single") {
509
+ const raw = (_a = resourceState == null ? void 0 : resourceState.table_form_record) == null ? void 0 : _a.capacity;
510
+ const num = Number(raw);
511
+ if (Number.isFinite(num) && num > 0)
512
+ return num;
513
+ return 1;
514
+ }
515
+ return 1;
516
+ };
517
+ return (payload, { bookingUuid, tempOrder }) => {
518
+ var _a;
519
+ const resourceId = tempOrder.resource_id ?? (resourceState == null ? void 0 : resourceState.relationId);
520
+ const pickOriginal = (value) => {
521
+ if (value && typeof value === "object" && !Array.isArray(value)) {
522
+ const original = value.original;
523
+ return typeof original === "string" && original.length > 0 ? original : void 0;
524
+ }
525
+ return void 0;
526
+ };
527
+ const mainField = pickOriginal(tempOrder.table_number) ?? pickOriginal((_a = resourceState == null ? void 0 : resourceState.table_form_record) == null ? void 0 : _a.name) ?? "";
528
+ const resourceEntry = resourceState && resourceId ? {
529
+ relation_type: "form",
530
+ like_status: "common",
531
+ id: Number(resourceId),
532
+ main_field: mainField,
533
+ form_id: resourceState.tableFormId,
534
+ relation_id: resourceState.relationId ?? resourceId,
535
+ capacity: resolveResourceCapacity(),
536
+ metadata: {}
537
+ } : void 0;
538
+ const ruleProductUid = ruleProduct ? (0, import_utils2.createUuidV4)() : void 0;
539
+ const bookingCapacityValue = resolveResourceCapacity();
540
+ const nextBookings = (payload.bookings || []).map((booking, idx) => ({
541
+ ...booking,
542
+ appointment_status: "started",
543
+ metadata: {
544
+ ...booking.metadata || {},
545
+ ...resourceSelectType ? { resource_select_type: resourceSelectType } : {},
546
+ ...resourceSelectType ? { capacity: [{ id: 0, value: bookingCapacityValue, name: "" }] } : {}
547
+ },
548
+ ...idx === 0 && resourceEntry ? { resources: [resourceEntry] } : {},
549
+ ...idx === 0 && ruleProductUid ? { product_uid: ruleProductUid } : {}
550
+ }));
551
+ const nextProducts = [...payload.products || []];
552
+ if (ruleProduct && ruleProductUid) {
553
+ const sellingPrice = String(ruleProduct.price ?? "0.00");
554
+ const originalPrice = String(
555
+ ruleProduct.original_price ?? ruleProduct.price ?? "0.00"
556
+ );
557
+ nextProducts.push({
558
+ product_id: ruleProduct.id,
559
+ product_variant_id: 0,
560
+ num: 1,
561
+ selling_price: sellingPrice,
562
+ original_price: originalPrice,
563
+ payment_price: sellingPrice,
564
+ is_charge_tax: ruleProduct.is_gst ?? 0,
565
+ product_option_item: [],
566
+ discount_list: [],
567
+ product_bundle: [],
568
+ booking_uid: bookingUuid,
569
+ metadata: {
570
+ is_rule: true,
571
+ unique_identification_number: ruleProductUid,
572
+ booking_uid: bookingUuid
573
+ }
574
+ });
575
+ }
576
+ return { ...payload, bookings: nextBookings, products: nextProducts };
577
+ };
578
+ }
417
579
  async submitScanOrder() {
418
- var _a, _b, _c, _d, _e;
580
+ var _a, _b, _c, _d, _e, _f, _g;
419
581
  this.logMethodStart("submitScanOrder");
420
582
  try {
421
583
  await this.validateBeforeSubmitByItemRule();
@@ -426,17 +588,26 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
426
588
  this.store.entryPaxNumber = pax;
427
589
  const tempOrderForSubmit = this.store.order.ensureTempOrder();
428
590
  tempOrderForSubmit.metadata = { ...tempOrderForSubmit.metadata, collect_pax: pax };
591
+ tempOrderForSubmit.delivery_type = "shop_service";
592
+ const resourceTableName = (_b = (_a = this.store.resource) == null ? void 0 : _a.table_form_record) == null ? void 0 : _b.name;
593
+ if (resourceTableName && typeof resourceTableName === "object") {
594
+ tempOrderForSubmit.table_number = resourceTableName;
595
+ } else {
596
+ delete tempOrderForSubmit.table_number;
597
+ }
429
598
  this.store.order.persistTempOrder();
599
+ const enhancePayload = this.buildSubmitPayloadEnhancer();
430
600
  const result = await this.store.order.submitTempOrder({
431
601
  cacheId: this.cacheId,
432
- platform: (_a = this.otherParams) == null ? void 0 : _a.platform,
433
- businessCode: (_b = this.otherParams) == null ? void 0 : _b.businessCode,
434
- channel: (_c = this.otherParams) == null ? void 0 : _c.channel,
435
- type: (_d = this.otherParams) == null ? void 0 : _d.type
602
+ platform: (_c = this.otherParams) == null ? void 0 : _c.platform,
603
+ businessCode: (_d = this.otherParams) == null ? void 0 : _d.businessCode,
604
+ channel: (_e = this.otherParams) == null ? void 0 : _e.channel,
605
+ type: (_f = this.otherParams) == null ? void 0 : _f.type,
606
+ enhancePayload
436
607
  });
437
608
  const tempOrder = this.store.order.getTempOrder();
438
609
  this.logMethodSuccess("submitScanOrder", {
439
- productCount: ((_e = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _e.length) || 0
610
+ productCount: ((_g = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _g.length) || 0
440
611
  });
441
612
  return result;
442
613
  } catch (error) {
@@ -857,20 +1028,22 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
857
1028
  strategyCount: Array.isArray(this.itemRuleRuntimeConfig.strategyConfigs) ? this.itemRuleRuntimeConfig.strategyConfigs.length : 0
858
1029
  });
859
1030
  }
860
- normalizeResourceState(config, hasOrderId) {
861
- var _a, _b;
862
- const orderNumberPrefix = Array.isArray(config == null ? void 0 : config.order_number_prefix) ? (config == null ? void 0 : config.order_number_prefix) || [] : [];
863
- const tableMaxNumber = Number((config == null ? void 0 : config.table_max_number) || 1);
864
- const orderCount = (0, import_utils.toNonNegativeNumber)(config == null ? void 0 : config.order_count);
865
- const currentOrderId = (0, import_utils.toPositiveString)(config == null ? void 0 : config.order_id);
866
- const lastOrderId = (0, import_utils.toPositiveString)(config == null ? void 0 : config.last_order_id);
867
- const relationId = (0, import_utils.toPositiveString)(config == null ? void 0 : config.relation_id);
868
- const tableFormId = (0, import_utils.toPositiveString)(config == null ? void 0 : config.table_form_id);
1031
+ normalizeResourceState(detail, resourceSelectType, hasOrderId) {
1032
+ var _a, _b, _c, _d;
1033
+ const currentOrderId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.order_id);
1034
+ const lastOrderId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.last_order_id);
1035
+ const relationId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.form_record_id);
1036
+ const tableFormId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.form_id);
1037
+ const formRecord = (detail == null ? void 0 : detail.form_record) ?? null;
869
1038
  const allowSnack = ((_b = (_a = this.otherParams) == null ? void 0 : _a.dineInConfig) == null ? void 0 : _b["workflow.allow_add_items"]) || false;
870
1039
  const deskmateValid = false;
871
- const isExclusive = tableMaxNumber > 0 ? tableMaxNumber <= 1 : false;
872
- const isFull = tableMaxNumber > 0 ? orderCount >= tableMaxNumber : false;
873
- const isBlock = tableMaxNumber === -1;
1040
+ const isExclusive = resourceSelectType === "single";
1041
+ const isFull = (0, import_utils.computeResourceIsFull)({
1042
+ resourceSelectType,
1043
+ lastOrderId,
1044
+ capacityList: ((_d = (_c = detail == null ? void 0 : detail.resource_capacity) == null ? void 0 : _c[0]) == null ? void 0 : _d.capacity_list) ?? [],
1045
+ capacity: formRecord == null ? void 0 : formRecord.capacity
1046
+ });
874
1047
  let availabilityInfo = {
875
1048
  mode: "idle",
876
1049
  deskmate_valid: deskmateValid
@@ -894,33 +1067,19 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
894
1067
  };
895
1068
  }
896
1069
  } else if (lastOrderId) {
897
- availabilityInfo = allowSnack ? {
898
- mode: deskmateValid ? "additional_order_with_code" : "additional_order",
899
- order_id: lastOrderId,
900
- relation_id: relationId,
901
- table_form_id: tableFormId,
902
- deskmate_valid: deskmateValid
903
- } : {
904
- mode: "resource_busy",
905
- order_id: lastOrderId,
906
- relation_id: relationId,
907
- table_form_id: tableFormId,
908
- deskmate_valid: deskmateValid
909
- };
910
- }
911
- if (isBlock) {
912
- availabilityInfo = {
913
- mode: "resource_block",
914
- order_id: lastOrderId,
915
- relation_id: relationId,
916
- table_form_id: tableFormId,
917
- deskmate_valid: deskmateValid
918
- };
1070
+ const canFallthroughToIdle = resourceSelectType === "multiple" && !isFull;
1071
+ if (!canFallthroughToIdle) {
1072
+ availabilityInfo = {
1073
+ mode: "resource_busy",
1074
+ order_id: "0",
1075
+ relation_id: relationId,
1076
+ table_form_id: tableFormId,
1077
+ deskmate_valid: deskmateValid
1078
+ };
1079
+ }
919
1080
  }
920
1081
  return {
921
1082
  ...availabilityInfo,
922
- tableMaxNumber,
923
- orderCount,
924
1083
  currentOrderId,
925
1084
  lastOrderId,
926
1085
  relationId,
@@ -929,27 +1088,46 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
929
1088
  deskmateValid,
930
1089
  isExclusive,
931
1090
  isFull,
932
- orderNumberPrefix,
933
- raw: config,
934
- table_form_record: (config == null ? void 0 : config.table_form_record) ?? null
1091
+ resourceSelectType,
1092
+ raw: detail,
1093
+ table_form_record: formRecord
935
1094
  };
936
1095
  }
937
- async fetchTableConfigByResourceId(resourceId) {
938
- const tableResourceId = Number(resourceId);
939
- if (!Number.isFinite(tableResourceId) || tableResourceId <= 0) {
1096
+ // 从首个预约规则商品的 product_resource.resources 中,按 form_id 匹配返回 type
1097
+ resolveResourceSelectType(formId) {
1098
+ var _a;
1099
+ const firstProduct = this.enabledReservationRuleProducts[0];
1100
+ const resources = ((_a = firstProduct == null ? void 0 : firstProduct.product_resource) == null ? void 0 : _a.resources) || [];
1101
+ const numericFormId = Number(formId);
1102
+ if (!Number.isFinite(numericFormId) || numericFormId <= 0)
1103
+ return void 0;
1104
+ const matched = resources.find((r) => Number(r == null ? void 0 : r.id) === numericFormId);
1105
+ return matched == null ? void 0 : matched.type;
1106
+ }
1107
+ async fetchResourceOccupyDetailByResourceId(resourceId) {
1108
+ var _a, _b, _c, _d;
1109
+ const formRecordId = Number(resourceId);
1110
+ if (!Number.isFinite(formRecordId) || formRecordId <= 0) {
940
1111
  throw new Error(`[ScanOrder] 非法桌台 resourceId: ${resourceId}`);
941
1112
  }
1113
+ const shopId = (_b = (_a = this.otherParams) == null ? void 0 : _a.getStateData) == null ? void 0 : _b.call(_a, "shop_id");
1114
+ if (!shopId) {
1115
+ throw new Error("[ScanOrder] 无法获取 shop_id");
1116
+ }
942
1117
  const response = await this.request.get(
943
- "/order/dining/table/config",
1118
+ "/order/resource/occupy-detail",
944
1119
  {
945
- table_resource_id: tableResourceId,
946
- with_table_form_info: 1
1120
+ shop_id: shopId,
1121
+ "form_record_ids[]": formRecordId,
1122
+ with_resource_capacity_info: 1,
1123
+ with_resource_order_info: 1,
1124
+ with_resource_form_info: 1
947
1125
  }
948
1126
  );
949
1127
  if (!(response == null ? void 0 : response.status)) {
950
- throw new Error((response == null ? void 0 : response.message) || "获取桌台配置失败");
1128
+ throw new Error((response == null ? void 0 : response.message) || "获取资源占用详情失败");
951
1129
  }
952
- return (response == null ? void 0 : response.data) || null;
1130
+ return ((_d = (_c = response == null ? void 0 : response.data) == null ? void 0 : _c.occupy_details) == null ? void 0 : _d[0]) ?? null;
953
1131
  }
954
1132
  // 检测当前链接是否可用
955
1133
  // 通过 resource_id + 店铺配置
@@ -971,46 +1149,48 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
971
1149
  const dineInConfig = (openData == null ? void 0 : openData.data) || {};
972
1150
  this.otherParams.dineInConfig = dineInConfig;
973
1151
  await this.syncItemRuleConfigsFromDineInConfig(dineInConfig);
974
- const shopClosedInfo = () => ({
1152
+ const closedBehaviorValue = dineInConfig == null ? void 0 : dineInConfig["availability.closed_behavior"];
1153
+ 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"]);
1154
+ const basicUnavailableMessage = (dineInConfig == null ? void 0 : dineInConfig["basic.unavailable_message"]) || closedMessage;
1155
+ const pauseMessage = (dineInConfig == null ? void 0 : dineInConfig["availability.pause_message"]) || closedMessage;
1156
+ const makeShopClosed = (errorTips, closed_behavior) => ({
975
1157
  mode: "shop_closed",
976
1158
  order_id: void 0,
977
1159
  relation_id: void 0,
978
1160
  table_form_id: void 0,
979
1161
  deskmate_valid: false,
980
- errorTips: (dineInConfig == null ? void 0 : dineInConfig["availability.pause_message"]) || (dineInConfig == null ? void 0 : dineInConfig["availability.closed_message"]) || (dineInConfig == null ? void 0 : dineInConfig["availability.message"]) || (dineInConfig == null ? void 0 : dineInConfig["basic.closed_message"])
1162
+ errorTips,
1163
+ closed_behavior
981
1164
  });
1165
+ if ((dineInConfig == null ? void 0 : dineInConfig["basic.enable"]) === false) {
1166
+ return makeShopClosed(basicUnavailableMessage);
1167
+ }
982
1168
  if ((0, import_utils.toBoolean)(dineInConfig == null ? void 0 : dineInConfig["availability.paused"])) {
983
1169
  if ((dineInConfig == null ? void 0 : dineInConfig["availability.pause_behavior"]) === "hide_all") {
984
- return shopClosedInfo();
1170
+ return makeShopClosed(pauseMessage);
985
1171
  }
986
1172
  }
987
- const config = await this.fetchTableConfigByResourceId(resourceId);
988
- const resourceState = this.normalizeResourceState(config, hasOrderId);
989
- this.store.resource = resourceState;
990
- const availabilityInfo = {
991
- mode: resourceState.mode,
992
- order_id: resourceState.order_id,
993
- relation_id: resourceState.relationId,
994
- table_form_id: resourceState.tableFormId,
995
- deskmate_valid: resourceState.deskmate_valid,
996
- table_form_record: resourceState.table_form_record,
997
- policy: (_c = config == null ? void 0 : config.table_form_record) == null ? void 0 : _c.policy,
998
- partyroom_booking: (_d = config == null ? void 0 : config.table_form_record) == null ? void 0 : _d.partyroom_booking
999
- };
1173
+ 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) : [];
1174
+ let outsideOperatingHours = false;
1175
+ if (operatingHourIds.length && this.store.schedule) {
1176
+ const scheduleList = this.store.schedule.getScheduleListByIds(operatingHourIds);
1177
+ if (scheduleList.length) {
1178
+ const now = (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
1179
+ outsideOperatingHours = !(0, import_getDateIsInSchedule.getDateIsInSchedule)(now, scheduleList);
1180
+ }
1181
+ }
1182
+ if (outsideOperatingHours && closedBehaviorValue !== "show_menu_disabled") {
1183
+ return makeShopClosed(closedMessage, closedBehaviorValue);
1184
+ }
1000
1185
  const tempOrder = this.ensureTempOrder();
1001
- tempOrder.relation_id = resourceId || ((_e = this.otherParams) == null ? void 0 : _e.relation_id);
1002
- tempOrder.table_form_id = resourceState.tableFormId;
1003
- tempOrder.resource_id = resourceId;
1004
1186
  const reservationLinkIds = (0, import_utils.collectLinkProductIdsFromReservationRules)(
1005
- dineInConfig["reservation.enabled_reservation_rules"]
1187
+ dineInConfig["fulfillment.enabled_resource_rules"]
1006
1188
  );
1189
+ let pendingRequestEntryPax;
1190
+ let pendingRequestPaxMin;
1191
+ let pendingRequestPaxMax;
1007
1192
  if (reservationLinkIds.length === 0) {
1008
1193
  this.enabledReservationRuleProducts = [];
1009
- if (this.store.resource) {
1010
- delete this.store.resource.requestEntryPax;
1011
- delete this.store.resource.requestPaxMin;
1012
- delete this.store.resource.requestPaxMax;
1013
- }
1014
1194
  } else {
1015
1195
  tempOrder.metadata = { ...tempOrder.metadata || {} };
1016
1196
  delete tempOrder.metadata.table_occupancy_duration;
@@ -1042,38 +1222,15 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
1042
1222
  tempOrder.metadata.table_occupancy_duration = occupancyMinutes;
1043
1223
  }
1044
1224
  if ((0, import_utils.hasCustomCapacityProduct)(loaded)) {
1045
- availabilityInfo.requestEntryPax = 1;
1046
- if (this.store.resource)
1047
- this.store.resource.requestEntryPax = 1;
1048
- delete availabilityInfo.requestPaxMin;
1049
- delete availabilityInfo.requestPaxMax;
1050
- if (this.store.resource) {
1051
- delete this.store.resource.requestPaxMin;
1052
- delete this.store.resource.requestPaxMax;
1053
- }
1225
+ pendingRequestEntryPax = 1;
1054
1226
  const paxBounds = (0, import_utils.pickFirstCustomCapacityPaxBounds)(loaded);
1055
- if ((paxBounds == null ? void 0 : paxBounds.min) !== void 0) {
1056
- availabilityInfo.requestPaxMin = paxBounds.min;
1057
- if (this.store.resource)
1058
- this.store.resource.requestPaxMin = paxBounds.min;
1059
- }
1060
- if ((paxBounds == null ? void 0 : paxBounds.max) !== void 0) {
1061
- availabilityInfo.requestPaxMax = paxBounds.max;
1062
- if (this.store.resource)
1063
- this.store.resource.requestPaxMax = paxBounds.max;
1064
- }
1065
- } else if (this.store.resource) {
1066
- delete this.store.resource.requestEntryPax;
1067
- delete this.store.resource.requestPaxMin;
1068
- delete this.store.resource.requestPaxMax;
1227
+ if ((paxBounds == null ? void 0 : paxBounds.min) !== void 0)
1228
+ pendingRequestPaxMin = paxBounds.min;
1229
+ if ((paxBounds == null ? void 0 : paxBounds.max) !== void 0)
1230
+ pendingRequestPaxMax = paxBounds.max;
1069
1231
  }
1070
1232
  } else {
1071
1233
  this.enabledReservationRuleProducts = [];
1072
- if (this.store.resource) {
1073
- delete this.store.resource.requestEntryPax;
1074
- delete this.store.resource.requestPaxMin;
1075
- delete this.store.resource.requestPaxMax;
1076
- }
1077
1234
  void this.addScanOrderLog({
1078
1235
  level: "error",
1079
1236
  title: "[ScanOrder] enabled_reservation_rules product query failed",
@@ -1084,6 +1241,41 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
1084
1241
  });
1085
1242
  }
1086
1243
  }
1244
+ const occupyDetail = await this.fetchResourceOccupyDetailByResourceId(resourceId);
1245
+ const resourceSelectType = this.resolveResourceSelectType(
1246
+ (0, import_utils.toPositiveString)(occupyDetail == null ? void 0 : occupyDetail.form_id)
1247
+ );
1248
+ const resourceState = this.normalizeResourceState(
1249
+ occupyDetail,
1250
+ resourceSelectType,
1251
+ hasOrderId
1252
+ );
1253
+ this.store.resource = resourceState;
1254
+ if (pendingRequestEntryPax !== void 0) {
1255
+ this.store.resource.requestEntryPax = pendingRequestEntryPax;
1256
+ }
1257
+ if (pendingRequestPaxMin !== void 0) {
1258
+ this.store.resource.requestPaxMin = pendingRequestPaxMin;
1259
+ }
1260
+ if (pendingRequestPaxMax !== void 0) {
1261
+ this.store.resource.requestPaxMax = pendingRequestPaxMax;
1262
+ }
1263
+ const availabilityInfo = {
1264
+ mode: resourceState.mode,
1265
+ order_id: resourceState.order_id,
1266
+ relation_id: resourceState.relationId,
1267
+ table_form_id: resourceState.tableFormId,
1268
+ deskmate_valid: resourceState.deskmate_valid,
1269
+ table_form_record: resourceState.table_form_record,
1270
+ policy: (_c = occupyDetail == null ? void 0 : occupyDetail.form_record) == null ? void 0 : _c.policy,
1271
+ partyroom_booking: (_d = occupyDetail == null ? void 0 : occupyDetail.form_record) == null ? void 0 : _d.partyroom_booking,
1272
+ ...this.store.resource.requestEntryPax !== void 0 ? { requestEntryPax: this.store.resource.requestEntryPax } : {},
1273
+ ...this.store.resource.requestPaxMin !== void 0 ? { requestPaxMin: this.store.resource.requestPaxMin } : {},
1274
+ ...this.store.resource.requestPaxMax !== void 0 ? { requestPaxMax: this.store.resource.requestPaxMax } : {}
1275
+ };
1276
+ tempOrder.relation_id = resourceId || ((_e = this.otherParams) == null ? void 0 : _e.relation_id);
1277
+ tempOrder.table_form_id = resourceState.tableFormId;
1278
+ tempOrder.resource_id = resourceId;
1087
1279
  (_f = this.store.order) == null ? void 0 : _f.persistTempOrder();
1088
1280
  if (availabilityInfo.mode === "idle") {
1089
1281
  await this.addNewOrder();
@@ -1117,6 +1309,11 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
1117
1309
  submissionIndex: hasOrderId ? 1 : 0,
1118
1310
  historicalItems
1119
1311
  });
1312
+ if (outsideOperatingHours && closedBehaviorValue === "show_menu_disabled") {
1313
+ availabilityInfo.mode = "submit_disabled";
1314
+ availabilityInfo.errorTips = closedMessage;
1315
+ availabilityInfo.closed_behavior = closedBehaviorValue;
1316
+ }
1120
1317
  this.logMethodSuccess("checkResourceAvailable", {
1121
1318
  resourceId,
1122
1319
  mode: availabilityInfo.mode,
@@ -1126,14 +1323,13 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
1126
1323
  persistedRelationId: tempOrder.relation_id,
1127
1324
  persistedResourceId: tempOrder.resource_id,
1128
1325
  deskmateValid: availabilityInfo.deskmate_valid,
1129
- orderCount: resourceState.orderCount,
1130
- tableMaxNumber: resourceState.tableMaxNumber,
1326
+ resourceSelectType: resourceState.resourceSelectType,
1131
1327
  isExclusive: resourceState.isExclusive,
1132
1328
  isFull: resourceState.isFull
1133
1329
  });
1134
1330
  return availabilityInfo;
1135
1331
  } catch (error) {
1136
- this.logMethodError("checkResourceAvailable", error, {
1332
+ this.logMethodError("checkResourceAvailable", error.message, {
1137
1333
  resourceId
1138
1334
  });
1139
1335
  throw error;
@@ -1176,7 +1372,7 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
1176
1372
  });
1177
1373
  return formattedRes;
1178
1374
  } catch (error) {
1179
- this.logMethodError("getProductList", error);
1375
+ this.logMethodError("getProductList", error.message);
1180
1376
  throw error;
1181
1377
  }
1182
1378
  }
@@ -1190,6 +1386,69 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
1190
1386
  this.otherParams = { ...this.otherParams, ...params };
1191
1387
  }
1192
1388
  }
1389
+ getUIStateBucketKey() {
1390
+ if (!this.cacheId)
1391
+ return null;
1392
+ return `${_ScanOrderImpl.UI_STATE_KEY_PREFIX}${this.cacheId}`;
1393
+ }
1394
+ readUIStateBucket() {
1395
+ var _a;
1396
+ const key = this.getUIStateBucketKey();
1397
+ if (!key || !((_a = this.window) == null ? void 0 : _a.sessionStorage))
1398
+ return {};
1399
+ try {
1400
+ const raw = this.window.sessionStorage.getItem(key) || "{}";
1401
+ const parsed = JSON.parse(raw);
1402
+ return parsed && typeof parsed === "object" ? parsed : {};
1403
+ } catch {
1404
+ return {};
1405
+ }
1406
+ }
1407
+ writeUIStateBucket(bucket) {
1408
+ var _a;
1409
+ const key = this.getUIStateBucketKey();
1410
+ if (!key || !((_a = this.window) == null ? void 0 : _a.sessionStorage))
1411
+ return;
1412
+ try {
1413
+ this.window.sessionStorage.setItem(key, JSON.stringify(bucket));
1414
+ } catch (error) {
1415
+ console.warn("[ScanOrder] writeUIStateBucket failed", error);
1416
+ }
1417
+ }
1418
+ setUIState(key, value) {
1419
+ if (!this.getUIStateBucketKey())
1420
+ return;
1421
+ const bucket = this.readUIStateBucket();
1422
+ bucket[key] = value;
1423
+ this.writeUIStateBucket(bucket);
1424
+ }
1425
+ getUIState(key) {
1426
+ if (!this.getUIStateBucketKey())
1427
+ return void 0;
1428
+ const bucket = this.readUIStateBucket();
1429
+ return bucket[key];
1430
+ }
1431
+ deleteUIState(key) {
1432
+ if (!this.getUIStateBucketKey())
1433
+ return;
1434
+ const bucket = this.readUIStateBucket();
1435
+ if (key in bucket) {
1436
+ delete bucket[key];
1437
+ this.writeUIStateBucket(bucket);
1438
+ }
1439
+ }
1440
+ // 整桶清空(用于扫新桌、提交成功、restoreOrder 等场景)
1441
+ clearUIState() {
1442
+ var _a;
1443
+ const key = this.getUIStateBucketKey();
1444
+ if (!key || !((_a = this.window) == null ? void 0 : _a.sessionStorage))
1445
+ return;
1446
+ try {
1447
+ this.window.sessionStorage.removeItem(key);
1448
+ } catch (error) {
1449
+ console.warn("[ScanOrder] clearUIState failed", error);
1450
+ }
1451
+ }
1193
1452
  async setEntryPaxNumber(number) {
1194
1453
  const pax = (0, import_utils2.normalizeSubmitCollectPaxValue)(number);
1195
1454
  this.store.entryPaxNumber = pax;
@@ -1209,7 +1468,43 @@ var ScanOrderImpl = class extends import_BaseModule.BaseModule {
1209
1468
  getEntryPaxNumber() {
1210
1469
  return this.store.entryPaxNumber;
1211
1470
  }
1471
+ // 读取取餐/送餐开关
1472
+ // 依赖 checkResourceAvailable 已缓存的 dineInConfig
1473
+ getFulfillmentModes() {
1474
+ var _a;
1475
+ this.logMethodStart("getFulfillmentModes");
1476
+ const dineInConfig = ((_a = this.otherParams) == null ? void 0 : _a.dineInConfig) || {};
1477
+ const result = {
1478
+ enablePickup: Boolean(dineInConfig["fulfillment.enable_pickup"]),
1479
+ enableTableService: Boolean(dineInConfig["fulfillment.enable_table_service"])
1480
+ };
1481
+ this.logMethodSuccess("getFulfillmentModes", result);
1482
+ return result;
1483
+ }
1484
+ // 判定后台是否开启客户自定义取餐标识
1485
+ // 依赖 checkResourceAvailable 已缓存的 dineInConfig
1486
+ checkManualPickupRef() {
1487
+ var _a;
1488
+ this.logMethodStart("checkManualPickupRef");
1489
+ const dineInConfig = ((_a = this.otherParams) == null ? void 0 : _a.dineInConfig) || {};
1490
+ const refMode = dineInConfig["fulfillment.fulfillment_ref_mode"];
1491
+ const manualInputType = dineInConfig["fulfillment.manual_input_type"];
1492
+ const enabled = refMode === "manual_input";
1493
+ const result = enabled ? { enabled: true, manualInputType } : { enabled: false };
1494
+ this.logMethodSuccess("checkManualPickupRef", {
1495
+ enabled,
1496
+ manualInputType: enabled ? manualInputType : void 0
1497
+ });
1498
+ return result;
1499
+ }
1212
1500
  };
1501
+ var ScanOrderImpl = _ScanOrderImpl;
1502
+ // ─── UI 状态缓存(按 cacheId 分桶,sessionStorage) ───
1503
+ //
1504
+ // 用于物料层持久化 UI 层面的轻量状态(如当前步骤、gate 标记、登录回跳意图等)。
1505
+ // 桶键:pisell.scanOrder.uiState:<cacheId>;内部以 JSON object 形式存储多个字段。
1506
+ // 无 cacheId 时所有方法自动降级为 no-op,上层不用判空。
1507
+ ScanOrderImpl.UI_STATE_KEY_PREFIX = "pisell.scanOrder.uiState:";
1213
1508
  // Annotate the CommonJS export names for ESM import in node:
1214
1509
  0 && (module.exports = {
1215
1510
  ScanOrderImpl,