@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
@@ -1,4 +1,4 @@
1
- import { OrderModule, ProductList, SalesSummaryModule, ScanOrderLogInput, ScanOrderLoggerModule, ScanOrderLoggerProviderConfig, ScanOrderLoggerProviderType } from '../../modules';
1
+ import { OrderModule, ProductList, SalesSummaryModule, ScanOrderLogInput, ScanOrderLoggerModule, ScanOrderLoggerProviderConfig, ScanOrderLoggerProviderType, ScheduleModule } from '../../modules';
2
2
  import type { QuantityCheckResult, QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
3
3
  /**
4
4
  * 扫码下单流程 hook
@@ -114,6 +114,9 @@ export interface ScanOrderTempOrder {
114
114
  shop_discount: string;
115
115
  surcharge_fee: string;
116
116
  note: string;
117
+ buzzer?: string;
118
+ delivery_type?: string;
119
+ table_number?: Record<string, any>;
117
120
  schedule_date: string;
118
121
  created_at: string;
119
122
  products: ScanOrderOrderProduct[];
@@ -134,14 +137,15 @@ export interface ScanOrderSubmitPayload extends Omit<ScanOrderTempOrder, 'platfo
134
137
  request_unique_idempotency_token?: string;
135
138
  form_record_ids?: Array<{
136
139
  form_id: number | string;
137
- form_record_ids: Array<number | string>;
140
+ form_record_id: number | string;
138
141
  }>;
139
142
  products: ScanOrderSubmitProduct[];
140
143
  }
141
- export type ScanOrderAvailabilityMode = 'idle' | 'shop_closed' | 'resource_block' | 'resource_busy' | 'additional_order_with_code' | 'additional_order';
144
+ export type ScanOrderAvailabilityMode = 'idle' | 'shop_closed' | 'submit_disabled' | 'resource_busy' | 'additional_order_with_code' | 'additional_order';
142
145
  export interface ScanOrderTableFormRecord {
143
146
  policy?: string | null;
144
147
  partyroom_booking?: string | null;
148
+ capacity?: number | string | null;
145
149
  [key: string]: any;
146
150
  }
147
151
  export interface ScanOrderAvailabilityInfo {
@@ -151,7 +155,9 @@ export interface ScanOrderAvailabilityInfo {
151
155
  table_form_id?: string;
152
156
  deskmate_valid?: boolean;
153
157
  errorTips?: string;
154
- /** `/order/dining/table/config` 返回的 `table_form_record` 原样透出 */
158
+ /** 透传 `availability.closed_behavior`,便于 UI 识别拦截类型(如 show_menu_disabled) */
159
+ closed_behavior?: string;
160
+ /** `/order/resource/occupy-detail` 返回的 `form_record` 原样透出 */
155
161
  table_form_record?: ScanOrderTableFormRecord | null;
156
162
  policy?: string | null;
157
163
  partyroom_booking?: string | null;
@@ -162,34 +168,36 @@ export interface ScanOrderAvailabilityInfo {
162
168
  /** 首个 `capacity.type === 'custom'` 商品里 `custom[0]` 的 max(人数上限) */
163
169
  requestPaxMax?: number;
164
170
  }
165
- export interface ScanOrderTableSnackConfig {
166
- snack?: boolean | number | string;
167
- table_validate?: boolean | number | string;
171
+ /** `resource_capacity[i].capacity_list[j]` */
172
+ export interface ScanOrderResourceCapacitySlot {
173
+ start_at?: string;
174
+ end_at?: string;
175
+ pax?: number | string;
168
176
  }
169
- export interface ScanOrderOrderNumberPrefixConfig {
170
- table_order?: string;
171
- pos?: string;
177
+ export interface ScanOrderResourceCapacity {
178
+ capacity?: number | string;
179
+ capacity_list?: ScanOrderResourceCapacitySlot[];
172
180
  }
173
- export interface ScanOrderTableConfigApiData {
174
- table_max_number?: number | string | null;
175
- order_count?: number | string | null;
181
+ /** `/order/resource/occupy-detail` 单条 `occupy_details[i]` */
182
+ export interface ScanOrderResourceOccupyDetail {
183
+ form_record_id?: number | string | null;
184
+ form_id?: number | string | null;
176
185
  order_id?: number | string | null;
177
186
  last_order_id?: number | string | null;
178
- relation_id?: number | string | null;
179
- table_form_id?: number | string | null;
180
- table_snack?: ScanOrderTableSnackConfig[] | null;
181
- order_number_prefix?: ScanOrderOrderNumberPrefixConfig[] | null;
187
+ resource_capacity?: ScanOrderResourceCapacity[] | null;
188
+ form_record?: ScanOrderTableFormRecord | null;
182
189
  [key: string]: any;
183
190
  }
184
- export interface ScanOrderTableConfigApiResponse {
191
+ export interface ScanOrderResourceOccupyDetailApiResponse {
185
192
  status?: boolean;
186
193
  code?: number;
187
194
  message?: string;
188
- data?: ScanOrderTableConfigApiData | null;
195
+ data?: {
196
+ occupy_details?: ScanOrderResourceOccupyDetail[] | null;
197
+ } | null;
189
198
  }
199
+ export type ScanOrderResourceSelectType = 'single' | 'multiple' | 'capacity';
190
200
  export interface ScanOrderResourceState extends ScanOrderAvailabilityInfo {
191
- tableMaxNumber: number;
192
- orderCount: number;
193
201
  relationId?: string;
194
202
  tableFormId?: string;
195
203
  currentOrderId?: string;
@@ -198,13 +206,14 @@ export interface ScanOrderResourceState extends ScanOrderAvailabilityInfo {
198
206
  deskmateValid: boolean;
199
207
  isExclusive: boolean;
200
208
  isFull: boolean;
201
- orderNumberPrefix: ScanOrderOrderNumberPrefixConfig[];
202
- raw: ScanOrderTableConfigApiData | null;
209
+ /** 来自首个预约规则商品 product_resource.resources 中与 form_id 匹配的 resource type */
210
+ resourceSelectType?: ScanOrderResourceSelectType;
211
+ raw: ScanOrderResourceOccupyDetail | null;
203
212
  }
204
213
  export interface ScanOrderState {
205
214
  entryContext: ScanOrderEntryContext | null;
206
215
  status: ScanOrderStatus;
207
- config: ScanOrderTableConfigApiData | null;
216
+ config: Record<string, any> | null;
208
217
  resource: ScanOrderResourceState | null;
209
218
  flow: Record<string, any>;
210
219
  error: string | null;
@@ -212,6 +221,7 @@ export interface ScanOrderState {
212
221
  order?: OrderModule;
213
222
  salesSummary?: SalesSummaryModule;
214
223
  scanOrderLogger?: ScanOrderLoggerModule;
224
+ schedule?: ScheduleModule;
215
225
  itemRuleQuantityLimits: QuantityLimitResult[];
216
226
  cartValidation: {
217
227
  passed: boolean | null;
@@ -1,4 +1,4 @@
1
- import { ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderSummary, ScanOrderTempOrder } from './types';
1
+ import { ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderResourceCapacitySlot, ScanOrderResourceSelectType, ScanOrderSummary, ScanOrderTempOrder } from './types';
2
2
  import type { CartItemSummary, ItemRuleBusinessData, PaxInfo, QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
3
3
  import type { StrategyConfig } from '../../model/strategy/type';
4
4
  import type { ProductData } from '../../modules/Product/types';
@@ -109,6 +109,18 @@ export declare function collectLinkProductIdsFromReservationRules(rules: unknown
109
109
  export declare function pickFirstDurationMinutesFromProducts(products: ProductData[]): number | undefined;
110
110
  /** 是否存在 capacity.type === 'custom' 的商品 */
111
111
  export declare function hasCustomCapacityProduct(products: ProductData[]): boolean;
112
+ /**
113
+ * 根据预约规则商品的 resource.type 计算桌台是否已被"占满"。
114
+ * - single:只要有 `lastOrderId` 即视为占用
115
+ * - multiple:当前时间落在 `capacity_list[i]` 的 `[start_at, end_at]`(inclusive)内的 pax 之和 > 总容量
116
+ * - 其他('capacity' / undefined):返回 false,不施加限制
117
+ */
118
+ export declare function computeResourceIsFull(params: {
119
+ resourceSelectType?: ScanOrderResourceSelectType;
120
+ lastOrderId?: string;
121
+ capacityList?: ScanOrderResourceCapacitySlot[];
122
+ capacity?: number | string | null;
123
+ }): boolean;
112
124
  /**
113
125
  * 在商品列表中找到第一个 `capacity.type === 'custom'` 的商品,取其 `custom` 数组第一项的 min/max。
114
126
  * 仅返回有限数字字段;若均无法解析则返回 `undefined`。
@@ -1,6 +1,8 @@
1
+ var __create = Object.create;
1
2
  var __defProp = Object.defineProperty;
2
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
4
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
7
  var __export = (target, all) => {
6
8
  for (var name in all)
@@ -14,6 +16,14 @@ var __copyProps = (to, from, except, desc) => {
14
16
  }
15
17
  return to;
16
18
  };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
17
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
28
 
19
29
  // src/solution/ScanOrder/utils.ts
@@ -25,6 +35,7 @@ __export(utils_exports, {
25
35
  buildProductKey: () => buildProductKey,
26
36
  buildQuantityLimitIndex: () => buildQuantityLimitIndex,
27
37
  collectLinkProductIdsFromReservationRules: () => collectLinkProductIdsFromReservationRules,
38
+ computeResourceIsFull: () => computeResourceIsFull,
28
39
  createEmptySummary: () => createEmptySummary,
29
40
  extractStrategyModelIdsFromTableConfig: () => extractStrategyModelIdsFromTableConfig,
30
41
  getProductIdentityIndex: () => getProductIdentityIndex,
@@ -46,6 +57,7 @@ __export(utils_exports, {
46
57
  toPriceString: () => toPriceString
47
58
  });
48
59
  module.exports = __toCommonJS(utils_exports);
60
+ var import_dayjs = __toESM(require("dayjs"));
49
61
  function createEmptySummary() {
50
62
  return {
51
63
  product_quantity: 0,
@@ -411,6 +423,30 @@ function hasCustomCapacityProduct(products) {
411
423
  return ((_a = p == null ? void 0 : p.capacity) == null ? void 0 : _a.type) === "custom";
412
424
  });
413
425
  }
426
+ function computeResourceIsFull(params) {
427
+ const { resourceSelectType, lastOrderId, capacityList, capacity } = params;
428
+ if (resourceSelectType === "single")
429
+ return Boolean(lastOrderId);
430
+ if (resourceSelectType !== "multiple")
431
+ return false;
432
+ const totalCapacity = Number(capacity);
433
+ if (!Number.isFinite(totalCapacity) || totalCapacity <= 0)
434
+ return false;
435
+ const now = (0, import_dayjs.default)();
436
+ let occupied = 0;
437
+ for (const slot of capacityList || []) {
438
+ const start = (0, import_dayjs.default)(slot == null ? void 0 : slot.start_at);
439
+ const end = (0, import_dayjs.default)(slot == null ? void 0 : slot.end_at);
440
+ if (!start.isValid() || !end.isValid())
441
+ continue;
442
+ if ((now.isAfter(start) || now.isSame(start)) && (now.isBefore(end) || now.isSame(end))) {
443
+ const pax = Number(slot == null ? void 0 : slot.pax);
444
+ if (Number.isFinite(pax) && pax > 0)
445
+ occupied += pax;
446
+ }
447
+ }
448
+ return occupied > totalCapacity;
449
+ }
414
450
  function pickFirstCustomCapacityPaxBounds(products) {
415
451
  for (const p of products) {
416
452
  const cap = p == null ? void 0 : p.capacity;
@@ -446,6 +482,7 @@ function pickFirstCustomCapacityPaxBounds(products) {
446
482
  buildProductKey,
447
483
  buildQuantityLimitIndex,
448
484
  collectLinkProductIdsFromReservationRules,
485
+ computeResourceIsFull,
449
486
  createEmptySummary,
450
487
  extractStrategyModelIdsFromTableConfig,
451
488
  getProductIdentityIndex,
@@ -92,25 +92,48 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
92
92
  /**
93
93
  * 切换单个时段的选中状态(选中/取消)。
94
94
  * 内部自动处理连续时段的合并与拆分,订单是唯一真相源。
95
+ *
96
+ * slot.productId 指定当前操作针对的是该 resourceId 下的哪一个商品。
97
+ * 同一资源下不同 productId 之间互相隔离,不会相互合并。
95
98
  */
96
99
  toggleSlot(slot: VenueSlotSelection): Promise<ScanOrderOrderProduct[]>;
97
100
  /**
98
101
  * 获取某资源当前选中的所有独立时段(从订单中解析)。
102
+ * 不传 productId 时返回该资源下所有商品的选中时段;传了则精确匹配。
99
103
  */
100
- getSelectedSlotsForResource(resourceId: number | string): VenueSlotSelection[];
104
+ getSelectedSlotsForResource(resourceId: number | string, productId?: number): VenueSlotSelection[];
105
+ /** getSelectedSlotsForResource 的 (resourceId, productId) 精确版,内部使用。 */
106
+ private getSelectedSlotsForResourceProduct;
101
107
  /**
102
108
  * 判断某个时段是否已选中。
109
+ * 不传 productId 时:只要该资源下任一商品在 startTime 被选中即返回 true;传了则精确匹配。
103
110
  */
104
- isSlotSelected(resourceId: number | string, startTime: string): boolean;
111
+ isSlotSelected(resourceId: number | string, startTime: string, productId?: number): boolean;
105
112
  /**
106
- * 获取所有已选时段(按资源分组)。
113
+ * 判断指定 (resourceId, productId, startTime) 格子是否应因其它已选项而被禁用。
114
+ * 规则:
115
+ * 1) 同一 resourceId 下若已选了另一个 productId 的同 startTime → 禁用
116
+ * 2) 当前 resource 是组合资源:若其任一 child resource 在 startTime 被选中 → 禁用
117
+ * 3) 当前 resource 是某些组合资源的 child:若该组合资源在 startTime 被选中 → 禁用
118
+ * 4) 两个组合资源的 child 集合有交集,且对方在该 startTime 被选中 → 禁用
119
+ */
120
+ isSlotDisabledBySelection(params: {
121
+ resourceId: number | string;
122
+ productId: number;
123
+ startTime: string;
124
+ }): boolean;
125
+ /**
126
+ * 获取所有已选时段(按资源分组)。每个 slot 上带 productId,便于 UI 做 per-product 判定。
107
127
  */
108
128
  getAllSelectedSlots(): Map<number | string, VenueSlotSelection[]>;
109
129
  /**
110
- * 对指定资源的订单商品进行 reconcile:
130
+ * 对指定 (resourceId, productId) 的订单商品进行 reconcile:
111
131
  * 清除旧商品 → 合并连续时段 → 重新写入。
132
+ * 同一场地下不同商品互不干扰,各自单独 reconcile。
112
133
  */
113
- private reconcileOrderForResource;
134
+ private reconcileOrderForResourceProduct;
135
+ /** 给定一个父 rawResource,返回其 combined_resource.resource_ids 对应的子 rawResource 列表。 */
136
+ private getCombinedChildRawResources;
114
137
  setSlotConfig(config: Partial<VenueBookingSlotConfig>): void;
115
138
  getSlotConfig(): VenueBookingSlotConfig;
116
139
  loadSchedules(): Promise<void>;