@pisell/pisellos 2.1.153 → 2.1.154

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.
@@ -1,6 +1,6 @@
1
1
  import { Module, ModuleOptions, PisellCore } from '../../types';
2
2
  import { BaseModule } from '../../modules/BaseModule';
3
- import { ScanOrderAddLogParams, ScanOrderAvailabilityInfo, ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderScanCodeResult, ScanOrderTempOrder } from './types';
3
+ import { ScanOrderAddLogParams, ScanOrderAvailabilityInfo, ScanOrderAllowAddItemsInfo, ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderReservationResourceSelectInfo, ScanOrderScanCodeResult, ScanOrderSyncAdditionalOrderResult, ScanOrderTempOrder } from './types';
4
4
  import type { UpdateProductInOrderParams } from '../../modules/Order/types';
5
5
  import type { Discount } from '../../modules/Discount/types';
6
6
  import { type CartItemSummary, type PaxInfo, type QuantityCheckResult, type QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
@@ -118,7 +118,8 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
118
118
  setItemRuleRuntimeConfig(config?: ScanOrderItemRuleRuntimeConfig): Promise<void>;
119
119
  private normalizeResourceState;
120
120
  private resolveResourceSelectType;
121
- private fetchResourceOccupyDetailByResourceId;
121
+ private fetchResourceOccupyDetailsByResourceId;
122
+ private resolveAdditionalOrderFromOccupyDetail;
122
123
  checkResourceAvailable(resourceId?: string | null, hasOrderId?: boolean): Promise<ScanOrderAvailabilityInfo>;
123
124
  getAdditionalOrderInfo(): Promise<{
124
125
  orderId: string;
@@ -142,6 +143,9 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
142
143
  clearUIState(): void;
143
144
  setEntryPaxNumber(number: number): Promise<void>;
144
145
  getEntryPaxNumber(): number | null;
146
+ syncAdditionalOrderFromResource(resourceId?: string | null): Promise<ScanOrderSyncAdditionalOrderResult>;
147
+ getReservationResourceSelectType(): ScanOrderReservationResourceSelectInfo;
148
+ checkAllowAddItems(): ScanOrderAllowAddItemsInfo;
145
149
  getFulfillmentModes(): {
146
150
  enablePickup: boolean;
147
151
  enableTableService: boolean;
@@ -1411,13 +1411,13 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1411
1411
  var resourceState = this.store.resource;
1412
1412
  var resourceSelectType = resourceState === null || resourceState === void 0 ? void 0 : resourceState.resourceSelectType;
1413
1413
 
1414
- // collect_pax 时的资源占用兜底:single 独占整张桌台,其余模式占 1 个容量位。
1415
- var resolveResourceCapacity = function resolveResourceCapacity() {
1414
+ // ScanOrder booking 容量只由预约规则决定:single 占用整张桌台,multiple 占用 1 个容量位。
1415
+ var resolveBookingCapacityValue = function resolveBookingCapacityValue() {
1416
1416
  if (resourceSelectType === 'single') {
1417
1417
  var _resourceState$table_;
1418
1418
  var raw = resourceState === null || resourceState === void 0 || (_resourceState$table_ = resourceState.table_form_record) === null || _resourceState$table_ === void 0 ? void 0 : _resourceState$table_.capacity;
1419
1419
  var num = Number(raw);
1420
- if (Number.isFinite(num) && num > 0) return num;
1420
+ if (Number.isFinite(num) && num > 0) return Math.max(1, Math.floor(num));
1421
1421
  return 1;
1422
1422
  }
1423
1423
  return 1;
@@ -1435,8 +1435,8 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1435
1435
  });
1436
1436
  }
1437
1437
  var rawCollectPax = (_tempOrder$metadata = tempOrder.metadata) === null || _tempOrder$metadata === void 0 ? void 0 : _tempOrder$metadata.collect_pax;
1438
- var hasCollectPaxForCapacity = rawCollectPax !== null && rawCollectPax !== undefined && rawCollectPax !== '';
1439
- var resourceCapacityValue = hasCollectPaxForCapacity ? normalizeSubmitCollectPaxValue(rawCollectPax) : resolveResourceCapacity();
1438
+ var hasExplicitCollectPax = rawCollectPax !== null && rawCollectPax !== undefined && rawCollectPax !== '';
1439
+ var bookingCapacityValue = resolveBookingCapacityValue();
1440
1440
  var pickOriginal = function pickOriginal(value) {
1441
1441
  if (value && _typeof(value) === 'object' && !Array.isArray(value)) {
1442
1442
  var original = value.original;
@@ -1452,21 +1452,25 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1452
1452
  main_field: mainField,
1453
1453
  form_id: resourceState.tableFormId,
1454
1454
  relation_id: (_resourceState$relati = resourceState.relationId) !== null && _resourceState$relati !== void 0 ? _resourceState$relati : resourceId,
1455
- capacity: resourceCapacityValue,
1455
+ capacity: bookingCapacityValue,
1456
1456
  metadata: _this5.buildScanOrderResourceMetadata({
1457
1457
  resourceState: resourceState,
1458
1458
  resourceName: mainField
1459
1459
  })
1460
1460
  } : undefined;
1461
1461
  var ruleProductUid = ruleProduct ? createUuidV4() : undefined;
1462
- // 有 collect_pax 时 booking/resource capacity 与 number 都代表本次 pax;否则使用资源占用兜底值。
1463
- var bookingCapacityValue = resourceCapacityValue;
1464
1462
  var bookingCapacityDimensionId = (_pickFirstCustomCapac = pickFirstCustomCapacityDimensionId(_this5.enabledReservationRuleProducts)) !== null && _pickFirstCustomCapac !== void 0 ? _pickFirstCustomCapac : 0;
1465
1463
  var nextBookings = (payload.bookings || []).map(function (booking, idx) {
1464
+ var metadata = _objectSpread({}, booking.metadata || {});
1465
+ if (hasExplicitCollectPax) {
1466
+ metadata.collect_pax = normalizeSubmitCollectPaxValue(rawCollectPax);
1467
+ } else {
1468
+ delete metadata.collect_pax;
1469
+ }
1466
1470
  return _objectSpread(_objectSpread(_objectSpread({}, booking), {}, {
1467
1471
  number: bookingCapacityValue,
1468
1472
  appointment_status: 'started',
1469
- metadata: _objectSpread(_objectSpread(_objectSpread({}, booking.metadata || {}), resourceSelectType ? {
1473
+ metadata: _objectSpread(_objectSpread(_objectSpread({}, metadata), resourceSelectType ? {
1470
1474
  resource_select_type: resourceSelectType
1471
1475
  } : {}), resourceSelectType ? {
1472
1476
  capacity: [{
@@ -1516,7 +1520,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1516
1520
  key: "submitScanOrder",
1517
1521
  value: function () {
1518
1522
  var _submitScanOrder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee18() {
1519
- var _this$store$resource, _this$otherParams5, _this$otherParams6, _this$otherParams7, _this$otherParams8, _tempOrder$products, pax, tempOrderForSubmit, resourceTableName, enhancePayload, result, tempOrder;
1523
+ var _this$store$resource, _this$otherParams5, _this$otherParams6, _this$otherParams7, _this$otherParams8, _tempOrder$products, tempOrderForSubmit, resourceTableName, enhancePayload, result, tempOrder;
1520
1524
  return _regeneratorRuntime().wrap(function _callee18$(_context18) {
1521
1525
  while (1) switch (_context18.prev = _context18.next) {
1522
1526
  case 0:
@@ -1531,12 +1535,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1531
1535
  }
1532
1536
  throw new Error('scanOrder解决方案需要 order 模块支持');
1533
1537
  case 6:
1534
- pax = normalizeSubmitCollectPaxValue(this.store.entryPaxNumber);
1535
- this.store.entryPaxNumber = pax;
1536
1538
  tempOrderForSubmit = this.store.order.ensureTempOrder();
1537
- tempOrderForSubmit.metadata = _objectSpread(_objectSpread({}, tempOrderForSubmit.metadata), {}, {
1538
- collect_pax: pax
1539
- });
1540
1539
  tempOrderForSubmit.delivery_type = 'shop_service';
1541
1540
  resourceTableName = (_this$store$resource = this.store.resource) === null || _this$store$resource === void 0 || (_this$store$resource = _this$store$resource.table_form_record) === null || _this$store$resource === void 0 ? void 0 : _this$store$resource.name;
1542
1541
  if (resourceTableName && _typeof(resourceTableName) === 'object') {
@@ -1546,7 +1545,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1546
1545
  }
1547
1546
  this.store.order.persistTempOrder();
1548
1547
  enhancePayload = this.buildSubmitPayloadEnhancer();
1549
- _context18.next = 17;
1548
+ _context18.next = 14;
1550
1549
  return this.store.order.submitTempOrder({
1551
1550
  cacheId: this.cacheId,
1552
1551
  platform: (_this$otherParams5 = this.otherParams) === null || _this$otherParams5 === void 0 ? void 0 : _this$otherParams5.platform,
@@ -1555,23 +1554,23 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1555
1554
  type: (_this$otherParams8 = this.otherParams) === null || _this$otherParams8 === void 0 ? void 0 : _this$otherParams8.type,
1556
1555
  enhancePayload: enhancePayload
1557
1556
  });
1558
- case 17:
1557
+ case 14:
1559
1558
  result = _context18.sent;
1560
1559
  tempOrder = this.store.order.getTempOrder();
1561
1560
  this.logMethodSuccess('submitScanOrder', {
1562
1561
  productCount: (tempOrder === null || tempOrder === void 0 || (_tempOrder$products = tempOrder.products) === null || _tempOrder$products === void 0 ? void 0 : _tempOrder$products.length) || 0
1563
1562
  });
1564
1563
  return _context18.abrupt("return", result);
1565
- case 23:
1566
- _context18.prev = 23;
1564
+ case 20:
1565
+ _context18.prev = 20;
1567
1566
  _context18.t0 = _context18["catch"](1);
1568
1567
  this.logMethodError('submitScanOrder', _context18.t0);
1569
1568
  throw _context18.t0;
1570
- case 27:
1569
+ case 24:
1571
1570
  case "end":
1572
1571
  return _context18.stop();
1573
1572
  }
1574
- }, _callee18, this, [[1, 23]]);
1573
+ }, _callee18, this, [[1, 20]]);
1575
1574
  }));
1576
1575
  function submitScanOrder() {
1577
1576
  return _submitScanOrder.apply(this, arguments);
@@ -2569,9 +2568,9 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
2569
2568
  return matched === null || matched === void 0 ? void 0 : matched.type;
2570
2569
  }
2571
2570
  }, {
2572
- key: "fetchResourceOccupyDetailByResourceId",
2571
+ key: "fetchResourceOccupyDetailsByResourceId",
2573
2572
  value: function () {
2574
- var _fetchResourceOccupyDetailByResourceId = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee36(resourceId) {
2573
+ var _fetchResourceOccupyDetailsByResourceId = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee36(resourceId) {
2575
2574
  var _this$otherParams10, _this$otherParams10$g, _response$data$occupy, _response$data;
2576
2575
  var formRecordId, shopId, response;
2577
2576
  return _regeneratorRuntime().wrap(function _callee36$(_context36) {
@@ -2607,18 +2606,68 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
2607
2606
  }
2608
2607
  throw new Error((response === null || response === void 0 ? void 0 : response.message) || '获取资源占用详情失败');
2609
2608
  case 11:
2610
- return _context36.abrupt("return", (_response$data$occupy = response === null || response === void 0 || (_response$data = response.data) === null || _response$data === void 0 || (_response$data = _response$data.occupy_details) === null || _response$data === void 0 ? void 0 : _response$data[0]) !== null && _response$data$occupy !== void 0 ? _response$data$occupy : null);
2609
+ return _context36.abrupt("return", (_response$data$occupy = response === null || response === void 0 || (_response$data = response.data) === null || _response$data === void 0 ? void 0 : _response$data.occupy_details) !== null && _response$data$occupy !== void 0 ? _response$data$occupy : []);
2611
2610
  case 12:
2612
2611
  case "end":
2613
2612
  return _context36.stop();
2614
2613
  }
2615
2614
  }, _callee36, this);
2616
2615
  }));
2617
- function fetchResourceOccupyDetailByResourceId(_x18) {
2618
- return _fetchResourceOccupyDetailByResourceId.apply(this, arguments);
2616
+ function fetchResourceOccupyDetailsByResourceId(_x18) {
2617
+ return _fetchResourceOccupyDetailsByResourceId.apply(this, arguments);
2618
+ }
2619
+ return fetchResourceOccupyDetailsByResourceId;
2620
+ }()
2621
+ }, {
2622
+ key: "resolveAdditionalOrderFromOccupyDetail",
2623
+ value: function resolveAdditionalOrderFromOccupyDetail(detail, resourceSelectType, allowAddItems) {
2624
+ var currentOrderId = toPositiveString(detail === null || detail === void 0 ? void 0 : detail.order_id);
2625
+ if (currentOrderId) {
2626
+ return {
2627
+ matched: true,
2628
+ order_id: currentOrderId
2629
+ };
2630
+ }
2631
+ var orderListIds = (Array.isArray(detail === null || detail === void 0 ? void 0 : detail.order_list) ? (detail === null || detail === void 0 ? void 0 : detail.order_list) || [] : []).map(function (order) {
2632
+ return toPositiveString(order === null || order === void 0 ? void 0 : order.id);
2633
+ }).filter(Boolean);
2634
+ if (resourceSelectType !== 'single') {
2635
+ return {
2636
+ matched: false,
2637
+ reason: 'no_order'
2638
+ };
2639
+ }
2640
+ if (!orderListIds.length) {
2641
+ return {
2642
+ matched: false,
2643
+ reason: 'no_order'
2644
+ };
2619
2645
  }
2620
- return fetchResourceOccupyDetailByResourceId;
2621
- }() // 检测当前链接是否可用
2646
+ if (!allowAddItems) {
2647
+ return {
2648
+ matched: false,
2649
+ reason: 'add_items_disabled'
2650
+ };
2651
+ }
2652
+ if (orderListIds.length === 1) {
2653
+ return {
2654
+ matched: true,
2655
+ order_id: orderListIds[0]
2656
+ };
2657
+ }
2658
+ if (orderListIds.length > 1) {
2659
+ return {
2660
+ matched: false,
2661
+ reason: 'multiple_orders'
2662
+ };
2663
+ }
2664
+ return {
2665
+ matched: false,
2666
+ reason: 'no_order'
2667
+ };
2668
+ }
2669
+
2670
+ // 检测当前链接是否可用
2622
2671
  // 通过 resource_id + 店铺配置
2623
2672
  // hasOrderId 表示 url 上是否有 orderid,如果是的话,后续的流程会走加单
2624
2673
  }, {
@@ -2633,6 +2682,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
2633
2682
  _this$otherParams12,
2634
2683
  _this$otherParams13,
2635
2684
  _this$otherParams13$g,
2685
+ _occupyDetails$,
2636
2686
  _occupyDetail$form_re,
2637
2687
  _occupyDetail$form_re2,
2638
2688
  _this$otherParams14,
@@ -2666,10 +2716,18 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
2666
2716
  occupancyMinutes,
2667
2717
  paxBounds,
2668
2718
  error,
2719
+ occupyDetails,
2669
2720
  occupyDetail,
2670
2721
  resourceSelectType,
2722
+ allowAddItems,
2723
+ additionalOrderResult,
2724
+ _occupyDetail$order_l,
2725
+ multipleOrdersState,
2726
+ _availabilityInfo,
2671
2727
  resourceState,
2728
+ additionalOrderId,
2672
2729
  availabilityInfo,
2730
+ isAdditionalOrderMode,
2673
2731
  _this$store$order7,
2674
2732
  _res$data,
2675
2733
  res,
@@ -2828,15 +2886,52 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
2828
2886
  });
2829
2887
  }
2830
2888
 
2831
- // Step2: 请求新的资源占用详情接口
2889
+ // Step2: 请求新的资源占用详情接口。occupy_details 第一维是资源,不是订单。
2832
2890
  _context37.next = 50;
2833
- return this.fetchResourceOccupyDetailByResourceId(normalizedResourceId);
2891
+ return this.fetchResourceOccupyDetailsByResourceId(normalizedResourceId);
2834
2892
  case 50:
2835
- occupyDetail = _context37.sent;
2836
- // Step3: 结合预约规则商品的 product_resource.resources 与占用接口返回的 form_id,
2893
+ occupyDetails = _context37.sent;
2894
+ occupyDetail = (_occupyDetails$ = occupyDetails[0]) !== null && _occupyDetails$ !== void 0 ? _occupyDetails$ : null; // Step3: 结合预约规则商品的 product_resource.resources 与占用接口返回的 form_id,
2837
2895
  // 计算当前桌台的 resourceSelectType(single/multiple/capacity)
2838
- resourceSelectType = this.resolveResourceSelectType(toPositiveString(occupyDetail === null || occupyDetail === void 0 ? void 0 : occupyDetail.form_id)); // Step4: 用 occupyDetail + resourceSelectType 规整为 resourceState
2896
+ resourceSelectType = this.resolveResourceSelectType(toPositiveString(occupyDetail === null || occupyDetail === void 0 ? void 0 : occupyDetail.form_id));
2897
+ allowAddItems = toBoolean(dineInConfig === null || dineInConfig === void 0 ? void 0 : dineInConfig['sale.allow_add_items']);
2898
+ additionalOrderResult = this.resolveAdditionalOrderFromOccupyDetail(occupyDetail, resourceSelectType, allowAddItems);
2899
+ if (!(additionalOrderResult.reason === 'multiple_orders')) {
2900
+ _context37.next = 61;
2901
+ break;
2902
+ }
2903
+ multipleOrdersState = _objectSpread(_objectSpread({}, this.normalizeResourceState(occupyDetail, resourceSelectType, hasOrderId)), {}, {
2904
+ mode: 'multiple_orders'
2905
+ });
2906
+ this.store.resource = multipleOrdersState;
2907
+ _availabilityInfo = {
2908
+ mode: 'multiple_orders',
2909
+ deskmate_valid: multipleOrdersState.deskmate_valid,
2910
+ relation_id: multipleOrdersState.relationId,
2911
+ table_form_id: multipleOrdersState.tableFormId,
2912
+ table_form_record: multipleOrdersState.table_form_record
2913
+ };
2914
+ this.logMethodSuccess('checkResourceAvailable', {
2915
+ resourceId: normalizedResourceId,
2916
+ mode: _availabilityInfo.mode,
2917
+ orderListCount: (occupyDetail === null || occupyDetail === void 0 || (_occupyDetail$order_l = occupyDetail.order_list) === null || _occupyDetail$order_l === void 0 ? void 0 : _occupyDetail$order_l.length) || 0,
2918
+ resourceSelectType: resourceSelectType
2919
+ });
2920
+ return _context37.abrupt("return", _availabilityInfo);
2921
+ case 61:
2922
+ // Step4: 用 occupyDetail + resourceSelectType 规整为 resourceState
2839
2923
  resourceState = this.normalizeResourceState(occupyDetail, resourceSelectType, hasOrderId);
2924
+ additionalOrderId = additionalOrderResult.order_id;
2925
+ if (additionalOrderId) {
2926
+ resourceState.mode = 'additional_order';
2927
+ resourceState.order_id = additionalOrderId;
2928
+ } else if (additionalOrderResult.reason === 'add_items_disabled') {
2929
+ resourceState.mode = 'resource_busy';
2930
+ resourceState.order_id = '0';
2931
+ } else if (resourceSelectType === 'multiple' && resourceState.isFull) {
2932
+ resourceState.mode = 'resource_busy';
2933
+ resourceState.order_id = '0';
2934
+ }
2840
2935
  this.store.resource = resourceState;
2841
2936
 
2842
2937
  // Step5: 把预约规则商品阶段暂存的 requestEntryPax 等注入 store.resource
@@ -2872,23 +2967,23 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
2872
2967
 
2873
2968
  // 空闲状态下自动准备本地临时订单,供后续“购物车式”商品操作使用
2874
2969
  if (!(availabilityInfo.mode === 'idle')) {
2875
- _context37.next = 65;
2970
+ _context37.next = 76;
2876
2971
  break;
2877
2972
  }
2878
- _context37.next = 65;
2973
+ _context37.next = 76;
2879
2974
  return this.addNewOrder();
2880
- case 65:
2881
- // 如果是加单模式,tempOrder 需要记录 lastOrderId,提交的时候走加单接口
2882
- if (availabilityInfo.mode === 'additional_order' || availabilityInfo.mode === 'additional_order_with_code') {
2883
- tempOrder.order_id = resourceState.lastOrderId;
2975
+ case 76:
2976
+ isAdditionalOrderMode = availabilityInfo.mode === 'additional_order' || availabilityInfo.mode === 'additional_order_with_code'; // 如果是加单模式,tempOrder 里需要记录目标订单 id,提交的时候走加单接口
2977
+ if (isAdditionalOrderMode) {
2978
+ tempOrder.order_id = additionalOrderId;
2884
2979
  }
2885
2980
  if (!tempOrder.order_id) {
2886
- _context37.next = 74;
2981
+ _context37.next = 86;
2887
2982
  break;
2888
2983
  }
2889
- _context37.next = 69;
2984
+ _context37.next = 81;
2890
2985
  return (_this$store$order7 = this.store.order) === null || _this$store$order7 === void 0 ? void 0 : _this$store$order7.getOrderInfoByRemote(tempOrder.order_id);
2891
- case 69:
2986
+ case 81:
2892
2987
  res = _context37.sent;
2893
2988
  // 找到下单的时候输入的 entryPaxNumber
2894
2989
  entryPaxNumber = res === null || res === void 0 || (_res$data = res.data) === null || _res$data === void 0 || (_res$data = _res$data.bookings) === null || _res$data === void 0 || (_res$data = _res$data.find(function (p) {
@@ -2896,14 +2991,14 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
2896
2991
  return (_p$metadata = p.metadata) === null || _p$metadata === void 0 ? void 0 : _p$metadata.collect_pax;
2897
2992
  })) === null || _res$data === void 0 || (_res$data = _res$data.metadata) === null || _res$data === void 0 ? void 0 : _res$data.collect_pax;
2898
2993
  if (!entryPaxNumber) {
2899
- _context37.next = 74;
2994
+ _context37.next = 86;
2900
2995
  break;
2901
2996
  }
2902
- _context37.next = 74;
2997
+ _context37.next = 86;
2903
2998
  return this.setEntryPaxNumber(entryPaxNumber);
2904
- case 74:
2999
+ case 86:
2905
3000
  lastOrderInfo = (_this$store$order8 = this.store.order) === null || _this$store$order8 === void 0 || (_this$store$order8$ge = _this$store$order8.getLastOrderInfo) === null || _this$store$order8$ge === void 0 ? void 0 : _this$store$order8$ge.call(_this$store$order8);
2906
- historicalItems = hasOrderId && Array.isArray(lastOrderInfo === null || lastOrderInfo === void 0 ? void 0 : lastOrderInfo.products) ? lastOrderInfo.products.reduce(function (acc, p) {
3001
+ historicalItems = isAdditionalOrderMode && Array.isArray(lastOrderInfo === null || lastOrderInfo === void 0 ? void 0 : lastOrderInfo.products) ? lastOrderInfo.products.reduce(function (acc, p) {
2907
3002
  if (typeof (p === null || p === void 0 ? void 0 : p.product_id) !== 'number') return acc;
2908
3003
  acc.push(_objectSpread({
2909
3004
  product_id: p.product_id,
@@ -2913,13 +3008,13 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
2913
3008
  } : {}));
2914
3009
  return acc;
2915
3010
  }, []) : []; // pax 由 setEntryPaxNumber 负责写入 itemRuleRuntimeConfig.pax
2916
- _context37.next = 78;
3011
+ _context37.next = 90;
2917
3012
  return this.setItemRuleRuntimeConfig({
2918
3013
  serviceType: (_this$otherParams15 = this.otherParams) === null || _this$otherParams15 === void 0 ? void 0 : _this$otherParams15.businessCode,
2919
- submissionIndex: hasOrderId ? 1 : 0,
3014
+ submissionIndex: isAdditionalOrderMode ? 1 : 0,
2920
3015
  historicalItems: historicalItems
2921
3016
  });
2922
- case 78:
3017
+ case 90:
2923
3018
  // operating_hours 超出营业时段 + closed_behavior=show_menu_disabled:
2924
3019
  // 允许浏览商品但 UI 层需拦截“下一步”,这里覆盖最终 mode 并回传错误提示
2925
3020
  if (outsideOperatingHours && closedBehaviorValue === 'show_menu_disabled') {
@@ -2941,18 +3036,18 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
2941
3036
  isFull: resourceState.isFull
2942
3037
  });
2943
3038
  return _context37.abrupt("return", availabilityInfo);
2944
- case 83:
2945
- _context37.prev = 83;
3039
+ case 95:
3040
+ _context37.prev = 95;
2946
3041
  _context37.t0 = _context37["catch"](3);
2947
3042
  this.logMethodError('checkResourceAvailable', _context37.t0.message, {
2948
3043
  resourceId: normalizedResourceId
2949
3044
  });
2950
3045
  throw _context37.t0;
2951
- case 87:
3046
+ case 99:
2952
3047
  case "end":
2953
3048
  return _context37.stop();
2954
3049
  }
2955
- }, _callee37, this, [[3, 83]]);
3050
+ }, _callee37, this, [[3, 95]]);
2956
3051
  }));
2957
3052
  function checkResourceAvailable(_x19) {
2958
3053
  return _checkResourceAvailable.apply(this, arguments);
@@ -3214,15 +3309,113 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
3214
3309
  value: function getEntryPaxNumber() {
3215
3310
  return this.store.entryPaxNumber;
3216
3311
  }
3312
+ }, {
3313
+ key: "syncAdditionalOrderFromResource",
3314
+ value: function () {
3315
+ var _syncAdditionalOrderFromResource = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee42(resourceId) {
3316
+ var _ref10, _ref11, _ref12, _this$store$resource2, _this$store$resource3, _occupyDetails$2, _this$store$resource4, _this$otherParams17, _this$store$order9;
3317
+ var tempOrder, normalizedResourceId, _result, occupyDetails, occupyDetail, resourceSelectType, allowAddItems, result;
3318
+ return _regeneratorRuntime().wrap(function _callee42$(_context42) {
3319
+ while (1) switch (_context42.prev = _context42.next) {
3320
+ case 0:
3321
+ tempOrder = this.ensureTempOrder();
3322
+ normalizedResourceId = String((_ref10 = (_ref11 = (_ref12 = resourceId !== null && resourceId !== void 0 ? resourceId : tempOrder.resource_id) !== null && _ref12 !== void 0 ? _ref12 : (_this$store$resource2 = this.store.resource) === null || _this$store$resource2 === void 0 ? void 0 : _this$store$resource2.relationId) !== null && _ref11 !== void 0 ? _ref11 : (_this$store$resource3 = this.store.resource) === null || _this$store$resource3 === void 0 ? void 0 : _this$store$resource3.relation_id) !== null && _ref10 !== void 0 ? _ref10 : '').trim();
3323
+ this.logMethodStart('syncAdditionalOrderFromResource', {
3324
+ resourceId: normalizedResourceId
3325
+ });
3326
+ if (normalizedResourceId) {
3327
+ _context42.next = 7;
3328
+ break;
3329
+ }
3330
+ _result = {
3331
+ matched: false,
3332
+ reason: 'missing_resource_id'
3333
+ };
3334
+ this.logMethodSuccess('syncAdditionalOrderFromResource', _result);
3335
+ return _context42.abrupt("return", _result);
3336
+ case 7:
3337
+ _context42.next = 9;
3338
+ return this.fetchResourceOccupyDetailsByResourceId(normalizedResourceId);
3339
+ case 9:
3340
+ occupyDetails = _context42.sent;
3341
+ occupyDetail = (_occupyDetails$2 = occupyDetails[0]) !== null && _occupyDetails$2 !== void 0 ? _occupyDetails$2 : null;
3342
+ resourceSelectType = ((_this$store$resource4 = this.store.resource) === null || _this$store$resource4 === void 0 ? void 0 : _this$store$resource4.resourceSelectType) || this.resolveResourceSelectType(toPositiveString(occupyDetail === null || occupyDetail === void 0 ? void 0 : occupyDetail.form_id));
3343
+ allowAddItems = toBoolean((_this$otherParams17 = this.otherParams) === null || _this$otherParams17 === void 0 || (_this$otherParams17 = _this$otherParams17.dineInConfig) === null || _this$otherParams17 === void 0 ? void 0 : _this$otherParams17['sale.allow_add_items']);
3344
+ result = this.resolveAdditionalOrderFromOccupyDetail(occupyDetail, resourceSelectType, allowAddItems);
3345
+ if (!(!result.matched || !result.order_id)) {
3346
+ _context42.next = 17;
3347
+ break;
3348
+ }
3349
+ this.logMethodSuccess('syncAdditionalOrderFromResource', _objectSpread(_objectSpread({}, result), {}, {
3350
+ resourceId: normalizedResourceId,
3351
+ resourceSelectType: resourceSelectType,
3352
+ allowAddItems: allowAddItems
3353
+ }));
3354
+ return _context42.abrupt("return", result);
3355
+ case 17:
3356
+ tempOrder.order_id = result.order_id;
3357
+ tempOrder.resource_id = normalizedResourceId;
3358
+ tempOrder.relation_id = toPositiveString(occupyDetail === null || occupyDetail === void 0 ? void 0 : occupyDetail.form_record_id) || normalizedResourceId || tempOrder.relation_id;
3359
+ tempOrder.table_form_id = toPositiveString(occupyDetail === null || occupyDetail === void 0 ? void 0 : occupyDetail.form_id) || tempOrder.table_form_id;
3360
+ (_this$store$order9 = this.store.order) === null || _this$store$order9 === void 0 || _this$store$order9.persistTempOrder();
3361
+ this.logMethodSuccess('syncAdditionalOrderFromResource', _objectSpread(_objectSpread({}, result), {}, {
3362
+ resourceId: normalizedResourceId,
3363
+ resourceSelectType: resourceSelectType,
3364
+ allowAddItems: allowAddItems
3365
+ }));
3366
+ return _context42.abrupt("return", result);
3367
+ case 24:
3368
+ case "end":
3369
+ return _context42.stop();
3370
+ }
3371
+ }, _callee42, this);
3372
+ }));
3373
+ function syncAdditionalOrderFromResource(_x22) {
3374
+ return _syncAdditionalOrderFromResource.apply(this, arguments);
3375
+ }
3376
+ return syncAdditionalOrderFromResource;
3377
+ }() // 读取预约规则商品的资源选择类型:single=单个预约,multiple=多个预约,capacity=容量型预约
3378
+ // 依赖 checkResourceAvailable 已根据预约规则商品与 occupy-detail 的 form_id 计算并缓存 store.resource
3379
+ }, {
3380
+ key: "getReservationResourceSelectType",
3381
+ value: function getReservationResourceSelectType() {
3382
+ var _this$store$resource5;
3383
+ this.logMethodStart('getReservationResourceSelectType');
3384
+ var resourceSelectType = (_this$store$resource5 = this.store.resource) === null || _this$store$resource5 === void 0 ? void 0 : _this$store$resource5.resourceSelectType;
3385
+ var result = _objectSpread(_objectSpread({}, resourceSelectType ? {
3386
+ resourceSelectType: resourceSelectType
3387
+ } : {}), {}, {
3388
+ isSingleReservation: resourceSelectType === 'single',
3389
+ isMultipleReservation: resourceSelectType === 'multiple',
3390
+ isCapacityReservation: resourceSelectType === 'capacity'
3391
+ });
3392
+ this.logMethodSuccess('getReservationResourceSelectType', result);
3393
+ return result;
3394
+ }
3395
+
3396
+ // 判定后台是否开启允许加餐
3397
+ // 依赖 checkResourceAvailable 已缓存的 dineInConfig
3398
+ }, {
3399
+ key: "checkAllowAddItems",
3400
+ value: function checkAllowAddItems() {
3401
+ var _this$otherParams18;
3402
+ this.logMethodStart('checkAllowAddItems');
3403
+ var dineInConfig = ((_this$otherParams18 = this.otherParams) === null || _this$otherParams18 === void 0 ? void 0 : _this$otherParams18.dineInConfig) || {};
3404
+ var result = {
3405
+ enabled: toBoolean(dineInConfig['sale.allow_add_items'])
3406
+ };
3407
+ this.logMethodSuccess('checkAllowAddItems', result);
3408
+ return result;
3409
+ }
3217
3410
 
3218
3411
  // 读取取餐/送餐开关
3219
3412
  // 依赖 checkResourceAvailable 已缓存的 dineInConfig
3220
3413
  }, {
3221
3414
  key: "getFulfillmentModes",
3222
3415
  value: function getFulfillmentModes() {
3223
- var _this$otherParams17;
3416
+ var _this$otherParams19;
3224
3417
  this.logMethodStart('getFulfillmentModes');
3225
- var dineInConfig = ((_this$otherParams17 = this.otherParams) === null || _this$otherParams17 === void 0 ? void 0 : _this$otherParams17.dineInConfig) || {};
3418
+ var dineInConfig = ((_this$otherParams19 = this.otherParams) === null || _this$otherParams19 === void 0 ? void 0 : _this$otherParams19.dineInConfig) || {};
3226
3419
  var result = {
3227
3420
  enablePickup: Boolean(dineInConfig['fulfillment.enable_pickup']),
3228
3421
  enableTableService: Boolean(dineInConfig['fulfillment.enable_table_service'])
@@ -3236,9 +3429,9 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
3236
3429
  }, {
3237
3430
  key: "checkManualPickupRef",
3238
3431
  value: function checkManualPickupRef() {
3239
- var _this$otherParams18;
3432
+ var _this$otherParams20;
3240
3433
  this.logMethodStart('checkManualPickupRef');
3241
- var dineInConfig = ((_this$otherParams18 = this.otherParams) === null || _this$otherParams18 === void 0 ? void 0 : _this$otherParams18.dineInConfig) || {};
3434
+ var dineInConfig = ((_this$otherParams20 = this.otherParams) === null || _this$otherParams20 === void 0 ? void 0 : _this$otherParams20.dineInConfig) || {};
3242
3435
  var refMode = dineInConfig['fulfillment.fulfillment_ref_mode'];
3243
3436
  var manualInputType = dineInConfig['fulfillment.manual_input_type'];
3244
3437
  var enabled = refMode === 'manual_input';
@@ -185,7 +185,7 @@ export interface ScanOrderSubmitPayload extends Omit<ScanOrderTempOrder, 'platfo
185
185
  }>;
186
186
  products: ScanOrderSubmitProduct[];
187
187
  }
188
- export type ScanOrderAvailabilityMode = 'idle' | 'shop_closed' | 'submit_disabled' | 'resource_busy' | 'additional_order_with_code' | 'additional_order';
188
+ export type ScanOrderAvailabilityMode = 'idle' | 'shop_closed' | 'submit_disabled' | 'resource_busy' | 'multiple_orders' | 'additional_order_with_code' | 'additional_order';
189
189
  export interface ScanOrderTableFormRecord {
190
190
  policy?: string | null;
191
191
  partyroom_booking?: string | null;
@@ -228,6 +228,10 @@ export interface ScanOrderResourceOccupyDetail {
228
228
  form_id?: number | string | null;
229
229
  order_id?: number | string | null;
230
230
  last_order_id?: number | string | null;
231
+ order_list?: Array<{
232
+ id?: number | string | null;
233
+ [key: string]: any;
234
+ }> | null;
231
235
  resource_capacity?: ScanOrderResourceCapacity[] | null;
232
236
  form_record?: ScanOrderTableFormRecord | null;
233
237
  [key: string]: any;
@@ -241,6 +245,21 @@ export interface ScanOrderResourceOccupyDetailApiResponse {
241
245
  } | null;
242
246
  }
243
247
  export type ScanOrderResourceSelectType = 'single' | 'multiple' | 'capacity';
248
+ export interface ScanOrderReservationResourceSelectInfo {
249
+ resourceSelectType?: ScanOrderResourceSelectType;
250
+ isSingleReservation: boolean;
251
+ isMultipleReservation: boolean;
252
+ isCapacityReservation: boolean;
253
+ }
254
+ export interface ScanOrderAllowAddItemsInfo {
255
+ enabled: boolean;
256
+ }
257
+ export type ScanOrderSyncAdditionalOrderReason = 'missing_resource_id' | 'no_order' | 'multiple_orders' | 'add_items_disabled' | 'invalid_order_id';
258
+ export interface ScanOrderSyncAdditionalOrderResult {
259
+ matched: boolean;
260
+ order_id?: string;
261
+ reason?: ScanOrderSyncAdditionalOrderReason;
262
+ }
244
263
  export interface ScanOrderResourceState extends ScanOrderAvailabilityInfo {
245
264
  relationId?: string;
246
265
  tableFormId?: string;
@@ -193,6 +193,7 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
193
193
  setUIState(key: string, value: any): void;
194
194
  getUIState<T = any>(key: string): T | undefined;
195
195
  deleteUIState(key: string): void;
196
+ setBookingHolder(bookingUid: string, holder: any): void;
196
197
  checkOpenDataAvailability(): Promise<OpenDataAvailabilityResult>;
197
198
  setOtherParams(params: Record<string, any>, { cover }?: {
198
199
  cover?: boolean;
@@ -3394,6 +3394,19 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
3394
3394
  this.writeUIStateBucket(bucket);
3395
3395
  }
3396
3396
  }
3397
+ }, {
3398
+ key: "setBookingHolder",
3399
+ value: function setBookingHolder(bookingUid, holder) {
3400
+ var _order$bookings;
3401
+ var order = this.getTempOrder();
3402
+ var booking = order === null || order === void 0 || (_order$bookings = order.bookings) === null || _order$bookings === void 0 ? void 0 : _order$bookings.find(function (b) {
3403
+ var _b$metadata4;
3404
+ return ((_b$metadata4 = b.metadata) === null || _b$metadata4 === void 0 ? void 0 : _b$metadata4.unique_identification_number) === bookingUid;
3405
+ });
3406
+ if (booking) {
3407
+ booking.holder = holder;
3408
+ }
3409
+ }
3397
3410
 
3398
3411
  // ─── OpenData 可用性 ───
3399
3412
  }, {
@@ -1,6 +1,6 @@
1
1
  import { Module, ModuleOptions, PisellCore } from '../../types';
2
2
  import { BaseModule } from '../../modules/BaseModule';
3
- import { ScanOrderAddLogParams, ScanOrderAvailabilityInfo, ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderScanCodeResult, ScanOrderTempOrder } from './types';
3
+ import { ScanOrderAddLogParams, ScanOrderAvailabilityInfo, ScanOrderAllowAddItemsInfo, ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderReservationResourceSelectInfo, ScanOrderScanCodeResult, ScanOrderSyncAdditionalOrderResult, ScanOrderTempOrder } from './types';
4
4
  import type { UpdateProductInOrderParams } from '../../modules/Order/types';
5
5
  import type { Discount } from '../../modules/Discount/types';
6
6
  import { type CartItemSummary, type PaxInfo, type QuantityCheckResult, type QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
@@ -118,7 +118,8 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
118
118
  setItemRuleRuntimeConfig(config?: ScanOrderItemRuleRuntimeConfig): Promise<void>;
119
119
  private normalizeResourceState;
120
120
  private resolveResourceSelectType;
121
- private fetchResourceOccupyDetailByResourceId;
121
+ private fetchResourceOccupyDetailsByResourceId;
122
+ private resolveAdditionalOrderFromOccupyDetail;
122
123
  checkResourceAvailable(resourceId?: string | null, hasOrderId?: boolean): Promise<ScanOrderAvailabilityInfo>;
123
124
  getAdditionalOrderInfo(): Promise<{
124
125
  orderId: string;
@@ -142,6 +143,9 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
142
143
  clearUIState(): void;
143
144
  setEntryPaxNumber(number: number): Promise<void>;
144
145
  getEntryPaxNumber(): number | null;
146
+ syncAdditionalOrderFromResource(resourceId?: string | null): Promise<ScanOrderSyncAdditionalOrderResult>;
147
+ getReservationResourceSelectType(): ScanOrderReservationResourceSelectInfo;
148
+ checkAllowAddItems(): ScanOrderAllowAddItemsInfo;
145
149
  getFulfillmentModes(): {
146
150
  enablePickup: boolean;
147
151
  enableTableService: boolean;
@@ -867,13 +867,13 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
867
867
  const ruleProduct = this.enabledReservationRuleProducts[0];
868
868
  const resourceState = this.store.resource;
869
869
  const resourceSelectType = resourceState == null ? void 0 : resourceState.resourceSelectType;
870
- const resolveResourceCapacity = () => {
870
+ const resolveBookingCapacityValue = () => {
871
871
  var _a;
872
872
  if (resourceSelectType === "single") {
873
873
  const raw = (_a = resourceState == null ? void 0 : resourceState.table_form_record) == null ? void 0 : _a.capacity;
874
874
  const num = Number(raw);
875
875
  if (Number.isFinite(num) && num > 0)
876
- return num;
876
+ return Math.max(1, Math.floor(num));
877
877
  return 1;
878
878
  }
879
879
  return 1;
@@ -892,8 +892,8 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
892
892
  };
893
893
  }
894
894
  const rawCollectPax = (_a = tempOrder.metadata) == null ? void 0 : _a.collect_pax;
895
- const hasCollectPaxForCapacity = rawCollectPax !== null && rawCollectPax !== void 0 && rawCollectPax !== "";
896
- const resourceCapacityValue = hasCollectPaxForCapacity ? (0, import_utils2.normalizeSubmitCollectPaxValue)(rawCollectPax) : resolveResourceCapacity();
895
+ const hasExplicitCollectPax = rawCollectPax !== null && rawCollectPax !== void 0 && rawCollectPax !== "";
896
+ const bookingCapacityValue = resolveBookingCapacityValue();
897
897
  const pickOriginal = (value) => {
898
898
  if (value && typeof value === "object" && !Array.isArray(value)) {
899
899
  const original = value.original;
@@ -909,35 +909,42 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
909
909
  main_field: mainField,
910
910
  form_id: resourceState.tableFormId,
911
911
  relation_id: resourceState.relationId ?? resourceId,
912
- capacity: resourceCapacityValue,
912
+ capacity: bookingCapacityValue,
913
913
  metadata: this.buildScanOrderResourceMetadata({
914
914
  resourceState,
915
915
  resourceName: mainField
916
916
  })
917
917
  } : void 0;
918
918
  const ruleProductUid = ruleProduct ? (0, import_utils2.createUuidV4)() : void 0;
919
- const bookingCapacityValue = resourceCapacityValue;
920
919
  const bookingCapacityDimensionId = (0, import_utils.pickFirstCustomCapacityDimensionId)(this.enabledReservationRuleProducts) ?? 0;
921
- const nextBookings = (payload.bookings || []).map((booking, idx) => ({
922
- ...booking,
923
- number: bookingCapacityValue,
924
- appointment_status: "started",
925
- metadata: {
926
- ...booking.metadata || {},
927
- ...resourceSelectType ? { resource_select_type: resourceSelectType } : {},
928
- ...resourceSelectType ? {
929
- capacity: [
930
- {
931
- id: bookingCapacityDimensionId,
932
- value: bookingCapacityValue,
933
- name: ""
934
- }
935
- ]
936
- } : {}
937
- },
938
- ...idx === 0 && resourceEntry ? { resources: [resourceEntry] } : {},
939
- ...idx === 0 && ruleProductUid ? { product_uid: ruleProductUid } : {}
940
- }));
920
+ const nextBookings = (payload.bookings || []).map((booking, idx) => {
921
+ const metadata = { ...booking.metadata || {} };
922
+ if (hasExplicitCollectPax) {
923
+ metadata.collect_pax = (0, import_utils2.normalizeSubmitCollectPaxValue)(rawCollectPax);
924
+ } else {
925
+ delete metadata.collect_pax;
926
+ }
927
+ return {
928
+ ...booking,
929
+ number: bookingCapacityValue,
930
+ appointment_status: "started",
931
+ metadata: {
932
+ ...metadata,
933
+ ...resourceSelectType ? { resource_select_type: resourceSelectType } : {},
934
+ ...resourceSelectType ? {
935
+ capacity: [
936
+ {
937
+ id: bookingCapacityDimensionId,
938
+ value: bookingCapacityValue,
939
+ name: ""
940
+ }
941
+ ]
942
+ } : {}
943
+ },
944
+ ...idx === 0 && resourceEntry ? { resources: [resourceEntry] } : {},
945
+ ...idx === 0 && ruleProductUid ? { product_uid: ruleProductUid } : {}
946
+ };
947
+ });
941
948
  const nextProducts = [...payload.products || []];
942
949
  if (ruleProduct && ruleProductUid && !tempOrder.order_id) {
943
950
  const sellingPrice = String(ruleProduct.price ?? "0.00");
@@ -974,10 +981,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
974
981
  if (!this.store.order) {
975
982
  throw new Error("scanOrder解决方案需要 order 模块支持");
976
983
  }
977
- const pax = (0, import_utils2.normalizeSubmitCollectPaxValue)(this.store.entryPaxNumber);
978
- this.store.entryPaxNumber = pax;
979
984
  const tempOrderForSubmit = this.store.order.ensureTempOrder();
980
- tempOrderForSubmit.metadata = { ...tempOrderForSubmit.metadata, collect_pax: pax };
981
985
  tempOrderForSubmit.delivery_type = "shop_service";
982
986
  const resourceTableName = (_b = (_a = this.store.resource) == null ? void 0 : _a.table_form_record) == null ? void 0 : _b.name;
983
987
  if (resourceTableName && typeof resourceTableName === "object") {
@@ -1524,8 +1528,8 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
1524
1528
  const matched = resources.find((r) => Number(r == null ? void 0 : r.id) === numericFormId);
1525
1529
  return matched == null ? void 0 : matched.type;
1526
1530
  }
1527
- async fetchResourceOccupyDetailByResourceId(resourceId) {
1528
- var _a, _b, _c, _d;
1531
+ async fetchResourceOccupyDetailsByResourceId(resourceId) {
1532
+ var _a, _b, _c;
1529
1533
  const formRecordId = Number(resourceId);
1530
1534
  if (!Number.isFinite(formRecordId) || formRecordId <= 0) {
1531
1535
  throw new Error(`[ScanOrder] 非法桌台 resourceId: ${resourceId}`);
@@ -1547,13 +1551,57 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
1547
1551
  if (!(response == null ? void 0 : response.status)) {
1548
1552
  throw new Error((response == null ? void 0 : response.message) || "获取资源占用详情失败");
1549
1553
  }
1550
- return ((_d = (_c = response == null ? void 0 : response.data) == null ? void 0 : _c.occupy_details) == null ? void 0 : _d[0]) ?? null;
1554
+ return ((_c = response == null ? void 0 : response.data) == null ? void 0 : _c.occupy_details) ?? [];
1555
+ }
1556
+ resolveAdditionalOrderFromOccupyDetail(detail, resourceSelectType, allowAddItems) {
1557
+ const currentOrderId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.order_id);
1558
+ if (currentOrderId) {
1559
+ return {
1560
+ matched: true,
1561
+ order_id: currentOrderId
1562
+ };
1563
+ }
1564
+ const orderListIds = (Array.isArray(detail == null ? void 0 : detail.order_list) ? (detail == null ? void 0 : detail.order_list) || [] : []).map((order) => (0, import_utils.toPositiveString)(order == null ? void 0 : order.id)).filter(Boolean);
1565
+ if (resourceSelectType !== "single") {
1566
+ return {
1567
+ matched: false,
1568
+ reason: "no_order"
1569
+ };
1570
+ }
1571
+ if (!orderListIds.length) {
1572
+ return {
1573
+ matched: false,
1574
+ reason: "no_order"
1575
+ };
1576
+ }
1577
+ if (!allowAddItems) {
1578
+ return {
1579
+ matched: false,
1580
+ reason: "add_items_disabled"
1581
+ };
1582
+ }
1583
+ if (orderListIds.length === 1) {
1584
+ return {
1585
+ matched: true,
1586
+ order_id: orderListIds[0]
1587
+ };
1588
+ }
1589
+ if (orderListIds.length > 1) {
1590
+ return {
1591
+ matched: false,
1592
+ reason: "multiple_orders"
1593
+ };
1594
+ }
1595
+ return {
1596
+ matched: false,
1597
+ reason: "no_order"
1598
+ };
1551
1599
  }
1552
1600
  // 检测当前链接是否可用
1553
1601
  // 通过 resource_id + 店铺配置
1554
1602
  // hasOrderId 表示 url 上是否有 orderid,如果是的话,后续的流程会走加单
1555
1603
  async checkResourceAvailable(resourceId, hasOrderId = false) {
1556
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
1604
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
1557
1605
  const normalizedResourceId = String(resourceId ?? "").trim();
1558
1606
  this.logMethodStart("checkResourceAvailable", {
1559
1607
  resourceId: normalizedResourceId
@@ -1669,15 +1717,54 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
1669
1717
  cacheId: this.cacheId
1670
1718
  });
1671
1719
  }
1672
- const occupyDetail = await this.fetchResourceOccupyDetailByResourceId(normalizedResourceId);
1720
+ const occupyDetails = await this.fetchResourceOccupyDetailsByResourceId(normalizedResourceId);
1721
+ const occupyDetail = occupyDetails[0] ?? null;
1673
1722
  const resourceSelectType = this.resolveResourceSelectType(
1674
1723
  (0, import_utils.toPositiveString)(occupyDetail == null ? void 0 : occupyDetail.form_id)
1675
1724
  );
1725
+ const allowAddItems = (0, import_utils.toBoolean)(dineInConfig == null ? void 0 : dineInConfig["sale.allow_add_items"]);
1726
+ const additionalOrderResult = this.resolveAdditionalOrderFromOccupyDetail(
1727
+ occupyDetail,
1728
+ resourceSelectType,
1729
+ allowAddItems
1730
+ );
1731
+ if (additionalOrderResult.reason === "multiple_orders") {
1732
+ const multipleOrdersState = {
1733
+ ...this.normalizeResourceState(occupyDetail, resourceSelectType, hasOrderId),
1734
+ mode: "multiple_orders"
1735
+ };
1736
+ this.store.resource = multipleOrdersState;
1737
+ const availabilityInfo2 = {
1738
+ mode: "multiple_orders",
1739
+ deskmate_valid: multipleOrdersState.deskmate_valid,
1740
+ relation_id: multipleOrdersState.relationId,
1741
+ table_form_id: multipleOrdersState.tableFormId,
1742
+ table_form_record: multipleOrdersState.table_form_record
1743
+ };
1744
+ this.logMethodSuccess("checkResourceAvailable", {
1745
+ resourceId: normalizedResourceId,
1746
+ mode: availabilityInfo2.mode,
1747
+ orderListCount: ((_e = occupyDetail == null ? void 0 : occupyDetail.order_list) == null ? void 0 : _e.length) || 0,
1748
+ resourceSelectType
1749
+ });
1750
+ return availabilityInfo2;
1751
+ }
1676
1752
  const resourceState = this.normalizeResourceState(
1677
1753
  occupyDetail,
1678
1754
  resourceSelectType,
1679
1755
  hasOrderId
1680
1756
  );
1757
+ const additionalOrderId = additionalOrderResult.order_id;
1758
+ if (additionalOrderId) {
1759
+ resourceState.mode = "additional_order";
1760
+ resourceState.order_id = additionalOrderId;
1761
+ } else if (additionalOrderResult.reason === "add_items_disabled") {
1762
+ resourceState.mode = "resource_busy";
1763
+ resourceState.order_id = "0";
1764
+ } else if (resourceSelectType === "multiple" && resourceState.isFull) {
1765
+ resourceState.mode = "resource_busy";
1766
+ resourceState.order_id = "0";
1767
+ }
1681
1768
  this.store.resource = resourceState;
1682
1769
  if (pendingRequestEntryPax !== void 0) {
1683
1770
  this.store.resource.requestEntryPax = pendingRequestEntryPax;
@@ -1695,34 +1782,35 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
1695
1782
  table_form_id: resourceState.tableFormId,
1696
1783
  deskmate_valid: resourceState.deskmate_valid,
1697
1784
  table_form_record: resourceState.table_form_record,
1698
- policy: (_e = occupyDetail == null ? void 0 : occupyDetail.form_record) == null ? void 0 : _e.policy,
1699
- partyroom_booking: (_f = occupyDetail == null ? void 0 : occupyDetail.form_record) == null ? void 0 : _f.partyroom_booking,
1785
+ policy: (_f = occupyDetail == null ? void 0 : occupyDetail.form_record) == null ? void 0 : _f.policy,
1786
+ partyroom_booking: (_g = occupyDetail == null ? void 0 : occupyDetail.form_record) == null ? void 0 : _g.partyroom_booking,
1700
1787
  ...this.store.resource.requestEntryPax !== void 0 ? { requestEntryPax: this.store.resource.requestEntryPax } : {},
1701
1788
  ...this.store.resource.requestPaxMin !== void 0 ? { requestPaxMin: this.store.resource.requestPaxMin } : {},
1702
1789
  ...this.store.resource.requestPaxMax !== void 0 ? { requestPaxMax: this.store.resource.requestPaxMax } : {}
1703
1790
  };
1704
- tempOrder.relation_id = normalizedResourceId || ((_g = this.otherParams) == null ? void 0 : _g.relation_id);
1791
+ tempOrder.relation_id = normalizedResourceId || ((_h = this.otherParams) == null ? void 0 : _h.relation_id);
1705
1792
  tempOrder.table_form_id = resourceState.tableFormId;
1706
1793
  tempOrder.resource_id = normalizedResourceId;
1707
- (_h = this.store.order) == null ? void 0 : _h.persistTempOrder();
1794
+ (_i = this.store.order) == null ? void 0 : _i.persistTempOrder();
1708
1795
  if (availabilityInfo.mode === "idle") {
1709
1796
  await this.addNewOrder();
1710
1797
  }
1711
- if (availabilityInfo.mode === "additional_order" || availabilityInfo.mode === "additional_order_with_code") {
1712
- tempOrder.order_id = resourceState.lastOrderId;
1798
+ const isAdditionalOrderMode = availabilityInfo.mode === "additional_order" || availabilityInfo.mode === "additional_order_with_code";
1799
+ if (isAdditionalOrderMode) {
1800
+ tempOrder.order_id = additionalOrderId;
1713
1801
  }
1714
1802
  if (tempOrder.order_id) {
1715
- const res = await ((_i = this.store.order) == null ? void 0 : _i.getOrderInfoByRemote(tempOrder.order_id));
1716
- const entryPaxNumber = (_m = (_l = (_k = (_j = res == null ? void 0 : res.data) == null ? void 0 : _j.bookings) == null ? void 0 : _k.find((p) => {
1803
+ const res = await ((_j = this.store.order) == null ? void 0 : _j.getOrderInfoByRemote(tempOrder.order_id));
1804
+ const entryPaxNumber = (_n = (_m = (_l = (_k = res == null ? void 0 : res.data) == null ? void 0 : _k.bookings) == null ? void 0 : _l.find((p) => {
1717
1805
  var _a2;
1718
1806
  return (_a2 = p.metadata) == null ? void 0 : _a2.collect_pax;
1719
- })) == null ? void 0 : _l.metadata) == null ? void 0 : _m.collect_pax;
1807
+ })) == null ? void 0 : _m.metadata) == null ? void 0 : _n.collect_pax;
1720
1808
  if (entryPaxNumber) {
1721
1809
  await this.setEntryPaxNumber(entryPaxNumber);
1722
1810
  }
1723
1811
  }
1724
- const lastOrderInfo = (_o = (_n = this.store.order) == null ? void 0 : _n.getLastOrderInfo) == null ? void 0 : _o.call(_n);
1725
- const historicalItems = hasOrderId && Array.isArray(lastOrderInfo == null ? void 0 : lastOrderInfo.products) ? lastOrderInfo.products.reduce((acc, p) => {
1812
+ const lastOrderInfo = (_p = (_o = this.store.order) == null ? void 0 : _o.getLastOrderInfo) == null ? void 0 : _p.call(_o);
1813
+ const historicalItems = isAdditionalOrderMode && Array.isArray(lastOrderInfo == null ? void 0 : lastOrderInfo.products) ? lastOrderInfo.products.reduce((acc, p) => {
1726
1814
  if (typeof (p == null ? void 0 : p.product_id) !== "number")
1727
1815
  return acc;
1728
1816
  acc.push({
@@ -1733,8 +1821,8 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
1733
1821
  return acc;
1734
1822
  }, []) : [];
1735
1823
  await this.setItemRuleRuntimeConfig({
1736
- serviceType: (_p = this.otherParams) == null ? void 0 : _p.businessCode,
1737
- submissionIndex: hasOrderId ? 1 : 0,
1824
+ serviceType: (_q = this.otherParams) == null ? void 0 : _q.businessCode,
1825
+ submissionIndex: isAdditionalOrderMode ? 1 : 0,
1738
1826
  historicalItems
1739
1827
  });
1740
1828
  if (outsideOperatingHours && closedBehaviorValue === "show_menu_disabled") {
@@ -1907,6 +1995,83 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
1907
1995
  getEntryPaxNumber() {
1908
1996
  return this.store.entryPaxNumber;
1909
1997
  }
1998
+ async syncAdditionalOrderFromResource(resourceId) {
1999
+ var _a, _b, _c, _d, _e, _f;
2000
+ const tempOrder = this.ensureTempOrder();
2001
+ const normalizedResourceId = String(
2002
+ resourceId ?? tempOrder.resource_id ?? ((_a = this.store.resource) == null ? void 0 : _a.relationId) ?? ((_b = this.store.resource) == null ? void 0 : _b.relation_id) ?? ""
2003
+ ).trim();
2004
+ this.logMethodStart("syncAdditionalOrderFromResource", {
2005
+ resourceId: normalizedResourceId
2006
+ });
2007
+ if (!normalizedResourceId) {
2008
+ const result2 = {
2009
+ matched: false,
2010
+ reason: "missing_resource_id"
2011
+ };
2012
+ this.logMethodSuccess("syncAdditionalOrderFromResource", result2);
2013
+ return result2;
2014
+ }
2015
+ const occupyDetails = await this.fetchResourceOccupyDetailsByResourceId(normalizedResourceId);
2016
+ const occupyDetail = occupyDetails[0] ?? null;
2017
+ const resourceSelectType = ((_c = this.store.resource) == null ? void 0 : _c.resourceSelectType) || this.resolveResourceSelectType((0, import_utils.toPositiveString)(occupyDetail == null ? void 0 : occupyDetail.form_id));
2018
+ const allowAddItems = (0, import_utils.toBoolean)(
2019
+ (_e = (_d = this.otherParams) == null ? void 0 : _d.dineInConfig) == null ? void 0 : _e["sale.allow_add_items"]
2020
+ );
2021
+ const result = this.resolveAdditionalOrderFromOccupyDetail(
2022
+ occupyDetail,
2023
+ resourceSelectType,
2024
+ allowAddItems
2025
+ );
2026
+ if (!result.matched || !result.order_id) {
2027
+ this.logMethodSuccess("syncAdditionalOrderFromResource", {
2028
+ ...result,
2029
+ resourceId: normalizedResourceId,
2030
+ resourceSelectType,
2031
+ allowAddItems
2032
+ });
2033
+ return result;
2034
+ }
2035
+ tempOrder.order_id = result.order_id;
2036
+ tempOrder.resource_id = normalizedResourceId;
2037
+ tempOrder.relation_id = (0, import_utils.toPositiveString)(occupyDetail == null ? void 0 : occupyDetail.form_record_id) || normalizedResourceId || tempOrder.relation_id;
2038
+ tempOrder.table_form_id = (0, import_utils.toPositiveString)(occupyDetail == null ? void 0 : occupyDetail.form_id) || tempOrder.table_form_id;
2039
+ (_f = this.store.order) == null ? void 0 : _f.persistTempOrder();
2040
+ this.logMethodSuccess("syncAdditionalOrderFromResource", {
2041
+ ...result,
2042
+ resourceId: normalizedResourceId,
2043
+ resourceSelectType,
2044
+ allowAddItems
2045
+ });
2046
+ return result;
2047
+ }
2048
+ // 读取预约规则商品的资源选择类型:single=单个预约,multiple=多个预约,capacity=容量型预约
2049
+ // 依赖 checkResourceAvailable 已根据预约规则商品与 occupy-detail 的 form_id 计算并缓存 store.resource
2050
+ getReservationResourceSelectType() {
2051
+ var _a;
2052
+ this.logMethodStart("getReservationResourceSelectType");
2053
+ const resourceSelectType = (_a = this.store.resource) == null ? void 0 : _a.resourceSelectType;
2054
+ const result = {
2055
+ ...resourceSelectType ? { resourceSelectType } : {},
2056
+ isSingleReservation: resourceSelectType === "single",
2057
+ isMultipleReservation: resourceSelectType === "multiple",
2058
+ isCapacityReservation: resourceSelectType === "capacity"
2059
+ };
2060
+ this.logMethodSuccess("getReservationResourceSelectType", result);
2061
+ return result;
2062
+ }
2063
+ // 判定后台是否开启允许加餐
2064
+ // 依赖 checkResourceAvailable 已缓存的 dineInConfig
2065
+ checkAllowAddItems() {
2066
+ var _a;
2067
+ this.logMethodStart("checkAllowAddItems");
2068
+ const dineInConfig = ((_a = this.otherParams) == null ? void 0 : _a.dineInConfig) || {};
2069
+ const result = {
2070
+ enabled: (0, import_utils.toBoolean)(dineInConfig["sale.allow_add_items"])
2071
+ };
2072
+ this.logMethodSuccess("checkAllowAddItems", result);
2073
+ return result;
2074
+ }
1910
2075
  // 读取取餐/送餐开关
1911
2076
  // 依赖 checkResourceAvailable 已缓存的 dineInConfig
1912
2077
  getFulfillmentModes() {
@@ -185,7 +185,7 @@ export interface ScanOrderSubmitPayload extends Omit<ScanOrderTempOrder, 'platfo
185
185
  }>;
186
186
  products: ScanOrderSubmitProduct[];
187
187
  }
188
- export type ScanOrderAvailabilityMode = 'idle' | 'shop_closed' | 'submit_disabled' | 'resource_busy' | 'additional_order_with_code' | 'additional_order';
188
+ export type ScanOrderAvailabilityMode = 'idle' | 'shop_closed' | 'submit_disabled' | 'resource_busy' | 'multiple_orders' | 'additional_order_with_code' | 'additional_order';
189
189
  export interface ScanOrderTableFormRecord {
190
190
  policy?: string | null;
191
191
  partyroom_booking?: string | null;
@@ -228,6 +228,10 @@ export interface ScanOrderResourceOccupyDetail {
228
228
  form_id?: number | string | null;
229
229
  order_id?: number | string | null;
230
230
  last_order_id?: number | string | null;
231
+ order_list?: Array<{
232
+ id?: number | string | null;
233
+ [key: string]: any;
234
+ }> | null;
231
235
  resource_capacity?: ScanOrderResourceCapacity[] | null;
232
236
  form_record?: ScanOrderTableFormRecord | null;
233
237
  [key: string]: any;
@@ -241,6 +245,21 @@ export interface ScanOrderResourceOccupyDetailApiResponse {
241
245
  } | null;
242
246
  }
243
247
  export type ScanOrderResourceSelectType = 'single' | 'multiple' | 'capacity';
248
+ export interface ScanOrderReservationResourceSelectInfo {
249
+ resourceSelectType?: ScanOrderResourceSelectType;
250
+ isSingleReservation: boolean;
251
+ isMultipleReservation: boolean;
252
+ isCapacityReservation: boolean;
253
+ }
254
+ export interface ScanOrderAllowAddItemsInfo {
255
+ enabled: boolean;
256
+ }
257
+ export type ScanOrderSyncAdditionalOrderReason = 'missing_resource_id' | 'no_order' | 'multiple_orders' | 'add_items_disabled' | 'invalid_order_id';
258
+ export interface ScanOrderSyncAdditionalOrderResult {
259
+ matched: boolean;
260
+ order_id?: string;
261
+ reason?: ScanOrderSyncAdditionalOrderReason;
262
+ }
244
263
  export interface ScanOrderResourceState extends ScanOrderAvailabilityInfo {
245
264
  relationId?: string;
246
265
  tableFormId?: string;
@@ -193,6 +193,7 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
193
193
  setUIState(key: string, value: any): void;
194
194
  getUIState<T = any>(key: string): T | undefined;
195
195
  deleteUIState(key: string): void;
196
+ setBookingHolder(bookingUid: string, holder: any): void;
196
197
  checkOpenDataAvailability(): Promise<OpenDataAvailabilityResult>;
197
198
  setOtherParams(params: Record<string, any>, { cover }?: {
198
199
  cover?: boolean;
@@ -1896,6 +1896,17 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1896
1896
  this.writeUIStateBucket(bucket);
1897
1897
  }
1898
1898
  }
1899
+ setBookingHolder(bookingUid, holder) {
1900
+ var _a;
1901
+ const order = this.getTempOrder();
1902
+ const booking = (_a = order == null ? void 0 : order.bookings) == null ? void 0 : _a.find((b) => {
1903
+ var _a2;
1904
+ return ((_a2 = b.metadata) == null ? void 0 : _a2.unique_identification_number) === bookingUid;
1905
+ });
1906
+ if (booking) {
1907
+ booking.holder = holder;
1908
+ }
1909
+ }
1899
1910
  // ─── OpenData 可用性 ───
1900
1911
  async checkOpenDataAvailability() {
1901
1912
  if (!this.store.openData)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "2.1.153",
4
+ "version": "2.1.154",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",