@pisell/pisellos 2.2.230 → 2.2.232

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 (34) hide show
  1. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  2. package/dist/modules/Order/index.js +44 -29
  3. package/dist/modules/Order/types.d.ts +14 -2
  4. package/dist/modules/Order/types.js +8 -1
  5. package/dist/modules/ProductList/index.d.ts +9 -12
  6. package/dist/modules/ProductList/index.js +122 -59
  7. package/dist/modules/ProductList/types.d.ts +14 -0
  8. package/dist/server/index.d.ts +21 -0
  9. package/dist/server/index.js +154 -34
  10. package/dist/server/utils/small-ticket.js +113 -29
  11. package/dist/solution/BookingByStep/index.d.ts +1 -1
  12. package/dist/solution/BookingTicket/index.d.ts +9 -1
  13. package/dist/solution/BookingTicket/index.js +198 -158
  14. package/dist/solution/BookingTicket/types.d.ts +4 -0
  15. package/dist/solution/BookingTicket/utils/cartView.js +20 -6
  16. package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +189 -0
  17. package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.js +429 -0
  18. package/lib/model/strategy/adapter/promotion/index.js +0 -49
  19. package/lib/modules/Order/index.js +18 -5
  20. package/lib/modules/Order/types.d.ts +14 -2
  21. package/lib/modules/ProductList/index.d.ts +9 -12
  22. package/lib/modules/ProductList/index.js +32 -4
  23. package/lib/modules/ProductList/types.d.ts +14 -0
  24. package/lib/server/index.d.ts +21 -0
  25. package/lib/server/index.js +107 -9
  26. package/lib/server/utils/small-ticket.js +78 -1
  27. package/lib/solution/BookingByStep/index.d.ts +1 -1
  28. package/lib/solution/BookingTicket/index.d.ts +9 -1
  29. package/lib/solution/BookingTicket/index.js +20 -1
  30. package/lib/solution/BookingTicket/types.d.ts +4 -0
  31. package/lib/solution/BookingTicket/utils/cartView.js +14 -7
  32. package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +189 -0
  33. package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +241 -0
  34. package/package.json +1 -1
@@ -1,49 +0,0 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
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
- ));
27
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
-
29
- // src/model/strategy/adapter/promotion/index.ts
30
- var promotion_exports = {};
31
- __export(promotion_exports, {
32
- BUY_X_GET_Y_FREE_STRATEGY: () => import_examples.BUY_X_GET_Y_FREE_STRATEGY,
33
- PromotionAdapter: () => import_adapter.PromotionAdapter,
34
- PromotionEvaluator: () => import_evaluator.PromotionEvaluator,
35
- X_ITEMS_FOR_Y_PRICE_STRATEGY: () => import_examples.X_ITEMS_FOR_Y_PRICE_STRATEGY,
36
- default: () => import_adapter2.default
37
- });
38
- module.exports = __toCommonJS(promotion_exports);
39
- var import_evaluator = require("./evaluator");
40
- var import_adapter = require("./adapter");
41
- var import_adapter2 = __toESM(require("./adapter"));
42
- var import_examples = require("./examples");
43
- // Annotate the CommonJS export names for ESM import in node:
44
- 0 && (module.exports = {
45
- BUY_X_GET_Y_FREE_STRATEGY,
46
- PromotionAdapter,
47
- PromotionEvaluator,
48
- X_ITEMS_FOR_Y_PRICE_STRATEGY
49
- });
@@ -534,6 +534,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
534
534
  * - 不主动调用 applyDiscount / recalculateSummary,调用方负责跟进。
535
535
  */
536
536
  async applyPromotion() {
537
+ var _a;
537
538
  if (this.isApplyingPromotion) {
538
539
  return;
539
540
  }
@@ -585,27 +586,39 @@ var OrderModule = class extends import_BaseModule.BaseModule {
585
586
  if (addAction.giftOptions.length === 1) {
586
587
  const sameStrategy = result.products.find(
587
588
  (p) => {
588
- var _a, _b;
589
- return ((_b = (_a = p.metadata) == null ? void 0 : _a._giftInfo) == null ? void 0 : _b.strategyId) === addAction.strategyId;
589
+ var _a2, _b;
590
+ return ((_b = (_a2 = p.metadata) == null ? void 0 : _a2._giftInfo) == null ? void 0 : _b.strategyId) === addAction.strategyId;
590
591
  }
591
592
  );
592
- if (sameStrategy) {
593
+ if (sameStrategy && !sameStrategy.booking_uid && !((_a = sameStrategy.metadata) == null ? void 0 : _a.booking_uid)) {
593
594
  sameStrategy.num = (Number(sameStrategy.num) || 0) + (addAction.giftCount || 1);
594
595
  continue;
595
596
  }
596
597
  }
597
598
  try {
598
- const giftProducts = await this.giftSelectResolver({
599
+ const giftResult = await this.giftSelectResolver({
599
600
  strategyId: addAction.strategyId,
600
601
  strategyName: addAction.strategyName,
601
602
  giftCount: addAction.giftCount,
602
603
  giftOptions: addAction.giftOptions,
603
604
  sourceProductIds: addAction.sourceProductIds
604
605
  });
606
+ const giftProducts = Array.isArray(giftResult) ? giftResult : giftResult == null ? void 0 : giftResult.products;
607
+ const giftBookings = Array.isArray(giftResult) ? [] : (giftResult == null ? void 0 : giftResult.bookings) || [];
605
608
  if (Array.isArray(giftProducts) && giftProducts.length > 0) {
606
- for (const gp of giftProducts) {
609
+ for (const [index, gp] of giftProducts.entries()) {
607
610
  if (!gp)
608
611
  continue;
612
+ const booking = giftBookings[index];
613
+ if (booking) {
614
+ const linked = this.createLinkedProductAndBooking({
615
+ product: gp,
616
+ booking
617
+ });
618
+ result.products.push(linked.product);
619
+ tempOrder.bookings = [...tempOrder.bookings || [], linked.booking];
620
+ continue;
621
+ }
609
622
  result.products.push(gp);
610
623
  }
611
624
  }
@@ -47,6 +47,18 @@ export interface OrderGiftSelectContext {
47
47
  /** 触发此赠品的主商品 metadata.unique_identification_number 列表 */
48
48
  sourceProductIds: string[];
49
49
  }
50
+ /**
51
+ * 赠品 resolver 返回值。
52
+ *
53
+ * @example
54
+ * return { products: [giftProduct], bookings: [giftBooking] };
55
+ */
56
+ export interface OrderGiftSelectResult {
57
+ /** 完整赠品购物车行,必须带 metadata._giftInfo。 */
58
+ products: Partial<OrderProduct>[];
59
+ /** 预约赠品对应的 booking,按 products 下标一一关联。 */
60
+ bookings?: AddProductBookingInput[];
61
+ }
50
62
  /**
51
63
  * 赠品解析回调签名(SDK → OS 的返回值)。
52
64
  *
@@ -54,9 +66,9 @@ export interface OrderGiftSelectContext {
54
66
  * - 多选项:SDK 弹窗等用户确认后构造
55
67
  * - 用户取消:抛错或返回空数组(OS 视为放弃本次添加)
56
68
  *
57
- * 返回的 OrderProduct 必须是完整的购物车行(含 metadata._giftInfo 标记),OS 会直接 push 入 tempOrder.products。
69
+ * 返回数组时沿用旧协议,只写 tempOrder.products;返回对象时可同时写入预约 bookings
58
70
  */
59
- export type OrderGiftSelectResolver = (ctx: OrderGiftSelectContext) => Promise<Partial<OrderProduct>[] | null>;
71
+ export type OrderGiftSelectResolver = (ctx: OrderGiftSelectContext) => Promise<Partial<OrderProduct>[] | OrderGiftSelectResult | null>;
60
72
  /** 未满足的促销策略(购物车底部 alert 渲染源) */
61
73
  export interface OrderUnfulfilledPromotion {
62
74
  strategyId: string;
@@ -1,5 +1,6 @@
1
1
  import { Module, PisellCore } from '../../types';
2
2
  import { BaseModule } from '../BaseModule';
3
+ import { ProductListLoadProductsParams } from './types';
3
4
  import { ProductData } from '../Product/types';
4
5
  export * from './types';
5
6
  export declare class ProductList extends BaseModule implements Module {
@@ -18,18 +19,14 @@ export declare class ProductList extends BaseModule implements Module {
18
19
  */
19
20
  updateOtherParams(params: Record<string, any>): void;
20
21
  storeChange(path?: string, value?: any): Promise<void>;
21
- loadProducts({ category_ids, product_ids, collection, menu_list_ids, customer_id: paramsCustomerId, with_count, schedule_datetime, schedule_date, cacheId, with_schedule, }: {
22
- category_ids?: number[];
23
- product_ids?: number[];
24
- collection?: number | string[];
25
- schedule_date?: string;
26
- cacheId?: string;
27
- customer_id?: number;
28
- menu_list_ids?: number[];
29
- schedule_datetime?: string;
30
- with_count?: string[];
31
- with_schedule?: number;
32
- }, options?: {
22
+ /**
23
+ * 获取加时商品列表。
24
+ *
25
+ * @example
26
+ * const products = await productList.getAddTimeProducts({ schedule_date: '2026-06-16' });
27
+ */
28
+ getAddTimeProducts(params?: ProductListLoadProductsParams): Promise<any>;
29
+ loadProducts({ category_ids, product_ids, collection, menu_list_ids, customer_id: paramsCustomerId, with_count, schedule_datetime, schedule_date, cacheId, with_schedule, extension_type, status, }?: ProductListLoadProductsParams, options?: {
33
30
  callback?: (result: any) => void;
34
31
  subscriberId?: string;
35
32
  }): Promise<any>;
@@ -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)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  return to;
16
18
  };
17
19
  var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/modules/ProductList/index.ts
@@ -25,6 +35,7 @@ __export(ProductList_exports, {
25
35
  module.exports = __toCommonJS(ProductList_exports);
26
36
  var import_BaseModule = require("../BaseModule");
27
37
  var import_lodash_es = require("lodash-es");
38
+ var import_dayjs = __toESM(require("dayjs"));
28
39
  __reExport(ProductList_exports, require("./types"), module.exports);
29
40
  var ProductList = class extends import_BaseModule.BaseModule {
30
41
  constructor(name, version) {
@@ -58,6 +69,20 @@ var ProductList = class extends import_BaseModule.BaseModule {
58
69
  }
59
70
  async storeChange(path, value) {
60
71
  }
72
+ /**
73
+ * 获取加时商品列表。
74
+ *
75
+ * @example
76
+ * const products = await productList.getAddTimeProducts({ schedule_date: '2026-06-16' });
77
+ */
78
+ async getAddTimeProducts(params = {}) {
79
+ return this.loadProducts({
80
+ schedule_date: (0, import_dayjs.default)().format("YYYY-MM-DD"),
81
+ status: "published",
82
+ ...params,
83
+ extension_type: ["product_add_time"]
84
+ });
85
+ }
61
86
  async loadProducts({
62
87
  category_ids = [],
63
88
  product_ids = [],
@@ -68,8 +93,10 @@ var ProductList = class extends import_BaseModule.BaseModule {
68
93
  schedule_datetime,
69
94
  schedule_date,
70
95
  cacheId,
71
- with_schedule
72
- }, options) {
96
+ with_schedule,
97
+ extension_type,
98
+ status = "published"
99
+ } = {}, options) {
73
100
  var _a, _b;
74
101
  let userPlugin = this.core.getPlugin("user");
75
102
  let customer_id = void 0;
@@ -92,7 +119,7 @@ var ProductList = class extends import_BaseModule.BaseModule {
92
119
  "event_item"
93
120
  ],
94
121
  with: ["category", "collection", "resourceRelation"],
95
- status: "published",
122
+ status,
96
123
  num: 500,
97
124
  skip: 1,
98
125
  customer_id,
@@ -107,7 +134,8 @@ var ProductList = class extends import_BaseModule.BaseModule {
107
134
  application_code: (_b = this.otherParams) == null ? void 0 : _b.channel,
108
135
  is_eject: 1,
109
136
  with_schedule,
110
- schedule_datetime
137
+ schedule_datetime,
138
+ extension_type
111
139
  },
112
140
  { osServer: true, callback: options == null ? void 0 : options.callback, subscriberId: options == null ? void 0 : options.subscriberId, customToast: () => {
113
141
  } }
@@ -1,4 +1,18 @@
1
1
  import { ProductData } from '../Product/types';
2
+ export interface ProductListLoadProductsParams {
3
+ category_ids?: number[];
4
+ product_ids?: number[];
5
+ collection?: number | string[];
6
+ schedule_date?: string;
7
+ cacheId?: string;
8
+ customer_id?: number;
9
+ menu_list_ids?: number[];
10
+ schedule_datetime?: string;
11
+ with_count?: string[];
12
+ with_schedule?: number;
13
+ extension_type?: string[];
14
+ status?: string;
15
+ }
2
16
  export interface ProductListData {
3
17
  list: ProductData[];
4
18
  selectProducts: ProductData[];
@@ -496,6 +496,27 @@ declare class Server {
496
496
  * 从订单中展开 bookings,再按条件筛选 + 分页
497
497
  */
498
498
  private computeBookingQueryResult;
499
+ /**
500
+ * 规范商品扩展类型过滤参数。
501
+ *
502
+ * @example
503
+ * const types = this.normalizeProductExtensionTypes(['product_add_time']);
504
+ */
505
+ private normalizeProductExtensionTypes;
506
+ /**
507
+ * 请求包含 product_add_time 时,按传入 extension_type 数组配置过滤商品。
508
+ *
509
+ * @example
510
+ * const list = this.filterProductsByExtensionTypes(products, ['product_add_time']);
511
+ */
512
+ private filterProductsByExtensionTypes;
513
+ /**
514
+ * 判断本次查询是否需要跳过餐牌过滤,直接按扩展类型拉商品。
515
+ *
516
+ * @example
517
+ * const skipMenu = this.shouldQueryProductsByExtensionTypes(['product_add_time']);
518
+ */
519
+ private shouldQueryProductsByExtensionTypes;
499
520
  /**
500
521
  * 商品查询的核心计算逻辑(编排 Products、Menu、Schedule 模块)
501
522
  * 供 handleProductQuery 首次返回及 pubsub 变更推送复用
@@ -208,26 +208,27 @@ var Server = class {
208
208
  */
209
209
  this.handleProductQuery = async ({ url, method, data, config }) => {
210
210
  console.log("[Server] handleProductQuery:", url, method, data, config);
211
- const { menu_list_ids, schedule_datetime, schedule_date, customer_id, ids } = data;
211
+ const { menu_list_ids, schedule_datetime, schedule_date, customer_id, ids, extension_type } = data;
212
212
  const { callback, subscriberId } = config || {};
213
213
  this.logInfo("handleProductQuery: 开始处理商品查询请求", {
214
214
  menu_list_ids,
215
215
  ids,
216
216
  schedule_datetime,
217
217
  schedule_date,
218
- customer_id
218
+ customer_id,
219
+ extension_type
219
220
  });
220
221
  if (subscriberId && typeof callback === "function") {
221
222
  this.productQuerySubscribers.set(subscriberId, {
222
223
  callback,
223
- context: { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id }
224
+ context: { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type }
224
225
  });
225
226
  this.logInfo("handleProductQuery: 已注册订阅者", {
226
227
  subscriberId,
227
228
  totalSubscribers: this.productQuerySubscribers.size
228
229
  });
229
230
  }
230
- return this.computeProductQueryResult({ menu_list_ids, ids, schedule_date, schedule_datetime, customer_id });
231
+ return this.computeProductQueryResult({ menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type });
231
232
  };
232
233
  /**
233
234
  * 按商品 id 查询单条(GET /shop/product/query/:productId)
@@ -2573,6 +2574,7 @@ var Server = class {
2573
2574
  if (!(0, import_small_ticket.hasSmallTicketData)((_a = printableOrder.payment_info) == null ? void 0 : _a.small_ticket_data)) {
2574
2575
  return { printed: false, order: printableOrder };
2575
2576
  }
2577
+ debugger;
2576
2578
  await this.dispatchPrintOtherReceiptTask({
2577
2579
  checkoutData: params.checkoutData,
2578
2580
  syncedOrder: printableOrder,
@@ -3470,6 +3472,38 @@ var Server = class {
3470
3472
  status: true
3471
3473
  };
3472
3474
  }
3475
+ /**
3476
+ * 规范商品扩展类型过滤参数。
3477
+ *
3478
+ * @example
3479
+ * const types = this.normalizeProductExtensionTypes(['product_add_time']);
3480
+ */
3481
+ normalizeProductExtensionTypes(extension_type) {
3482
+ if (!Array.isArray(extension_type))
3483
+ return [];
3484
+ return extension_type.map((item) => String(item || "").trim()).filter(Boolean);
3485
+ }
3486
+ /**
3487
+ * 请求包含 product_add_time 时,按传入 extension_type 数组配置过滤商品。
3488
+ *
3489
+ * @example
3490
+ * const list = this.filterProductsByExtensionTypes(products, ['product_add_time']);
3491
+ */
3492
+ filterProductsByExtensionTypes(products, extension_type) {
3493
+ const extensionTypes = this.normalizeProductExtensionTypes(extension_type);
3494
+ if (!extensionTypes.includes("product_add_time"))
3495
+ return products;
3496
+ return products.filter((product) => extensionTypes.includes(String((product == null ? void 0 : product.extension_type) || "")));
3497
+ }
3498
+ /**
3499
+ * 判断本次查询是否需要跳过餐牌过滤,直接按扩展类型拉商品。
3500
+ *
3501
+ * @example
3502
+ * const skipMenu = this.shouldQueryProductsByExtensionTypes(['product_add_time']);
3503
+ */
3504
+ shouldQueryProductsByExtensionTypes(extension_type) {
3505
+ return this.normalizeProductExtensionTypes(extension_type).includes("product_add_time");
3506
+ }
3473
3507
  /**
3474
3508
  * 商品查询的核心计算逻辑(编排 Products、Menu、Schedule 模块)
3475
3509
  * 供 handleProductQuery 首次返回及 pubsub 变更推送复用
@@ -3479,7 +3513,7 @@ var Server = class {
3479
3513
  */
3480
3514
  async computeProductQueryResult(context, options) {
3481
3515
  const tTotal = performance.now();
3482
- const { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, product_id } = context;
3516
+ const { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type, product_id } = context;
3483
3517
  const queryIds = Array.isArray(ids) ? ids.map((id) => Number(id)).filter((id) => Number.isFinite(id)) : [];
3484
3518
  this.logInfo("computeProductQueryResult 开始", {
3485
3519
  menuListIdsCount: (menu_list_ids == null ? void 0 : menu_list_ids.length) ?? 0,
@@ -3487,6 +3521,7 @@ var Server = class {
3487
3521
  schedule_datetime,
3488
3522
  schedule_date,
3489
3523
  customer_id,
3524
+ extension_type,
3490
3525
  product_id,
3491
3526
  changedIds: options == null ? void 0 : options.changedIds
3492
3527
  });
@@ -3510,18 +3545,19 @@ var Server = class {
3510
3545
  ids: uniqueIds
3511
3546
  });
3512
3547
  const filteredProducts2 = productsWithPrice.filter((p) => uniqueIds.includes(Number(p == null ? void 0 : p.id))).filter((p) => ((p == null ? void 0 : p.status) || "published") === "published");
3548
+ const extensionFilteredProducts = this.filterProductsByExtensionTypes(filteredProducts2, extension_type);
3513
3549
  (0, import_product.perfMark)("computeProductQueryResult", performance.now() - tTotal, {
3514
3550
  mode: "ids",
3515
3551
  ids: uniqueIds,
3516
- count: filteredProducts2.length
3552
+ count: extensionFilteredProducts.length
3517
3553
  });
3518
3554
  this.logInfo("computeProductQueryResult 完成(ids)", {
3519
3555
  ids: uniqueIds,
3520
- count: filteredProducts2.length
3556
+ count: extensionFilteredProducts.length
3521
3557
  });
3522
3558
  return {
3523
3559
  code: 200,
3524
- data: { list: filteredProducts2, count: filteredProducts2.length },
3560
+ data: { list: extensionFilteredProducts, count: extensionFilteredProducts.length },
3525
3561
  message: "",
3526
3562
  status: true
3527
3563
  };
@@ -3538,7 +3574,10 @@ var Server = class {
3538
3574
  count: allProductsWithPrice.length,
3539
3575
  productId: pid
3540
3576
  });
3541
- const published = allProductsWithPrice.filter((p) => ((p == null ? void 0 : p.status) || "published") === "published");
3577
+ const published = this.filterProductsByExtensionTypes(
3578
+ allProductsWithPrice.filter((p) => ((p == null ? void 0 : p.status) || "published") === "published"),
3579
+ extension_type
3580
+ );
3542
3581
  const item = published.find((p) => Number(p.id) === pid) ?? null;
3543
3582
  (0, import_product.perfMark)("computeProductQueryResult", performance.now() - tTotal, {
3544
3583
  mode: "single",
@@ -3556,6 +3595,57 @@ var Server = class {
3556
3595
  status: true
3557
3596
  };
3558
3597
  }
3598
+ if (this.shouldQueryProductsByExtensionTypes(extension_type)) {
3599
+ const tPrice2 = performance.now();
3600
+ let filteredProducts2 = await this.products.getProductsWithPrice(schedule_date, {
3601
+ scheduleModule: this.getSchedule(),
3602
+ schedule_datetime,
3603
+ customer_id
3604
+ }, {
3605
+ changedIds: options == null ? void 0 : options.changedIds
3606
+ });
3607
+ (0, import_product.perfMark)("computeQuery.getProductsWithPrice(extensionType)", performance.now() - tPrice2, {
3608
+ count: filteredProducts2.length,
3609
+ extension_type
3610
+ });
3611
+ const tStatus2 = performance.now();
3612
+ const beforeStatusCount2 = filteredProducts2.length;
3613
+ filteredProducts2 = filteredProducts2.filter((p) => ((p == null ? void 0 : p.status) || "published") === "published");
3614
+ (0, import_product.perfMark)("computeQuery.filterByStatus(extensionType)", performance.now() - tStatus2, {
3615
+ before: beforeStatusCount2,
3616
+ after: filteredProducts2.length
3617
+ });
3618
+ const tExtensionType2 = performance.now();
3619
+ const beforeExtensionTypeCount2 = filteredProducts2.length;
3620
+ filteredProducts2 = this.filterProductsByExtensionTypes(filteredProducts2, extension_type);
3621
+ (0, import_product.perfMark)("computeQuery.filterByExtensionType(extensionType)", performance.now() - tExtensionType2, {
3622
+ before: beforeExtensionTypeCount2,
3623
+ after: filteredProducts2.length,
3624
+ extension_type
3625
+ });
3626
+ const tSort2 = performance.now();
3627
+ filteredProducts2 = filteredProducts2.sort((a, b) => {
3628
+ const sortDiff = Number(b.sort) - Number(a.sort);
3629
+ if (sortDiff !== 0)
3630
+ return sortDiff;
3631
+ return (a.title || "").localeCompare(b.title || "");
3632
+ });
3633
+ (0, import_product.perfMark)("computeQuery.sort(extensionType)", performance.now() - tSort2, { count: filteredProducts2.length });
3634
+ (0, import_product.perfMark)("computeProductQueryResult", performance.now() - tTotal, {
3635
+ mode: "extensionType",
3636
+ filteredCount: filteredProducts2.length
3637
+ });
3638
+ this.logInfo("computeProductQueryResult 完成(extension_type)", {
3639
+ filteredCount: filteredProducts2.length,
3640
+ extension_type
3641
+ });
3642
+ return {
3643
+ code: 200,
3644
+ data: { list: filteredProducts2, count: filteredProducts2.length },
3645
+ message: "",
3646
+ status: true
3647
+ };
3648
+ }
3559
3649
  if (!this.menu) {
3560
3650
  this.logError("computeProductQueryResult: Menu 模块未注册");
3561
3651
  return { message: "Menu 模块未注册", data: { list: [], count: 0 } };
@@ -3605,6 +3695,14 @@ var Server = class {
3605
3695
  before: beforeStatusCount,
3606
3696
  after: filteredProducts.length
3607
3697
  });
3698
+ const tExtensionType = performance.now();
3699
+ const beforeExtensionTypeCount = filteredProducts.length;
3700
+ filteredProducts = this.filterProductsByExtensionTypes(filteredProducts, extension_type);
3701
+ (0, import_product.perfMark)("computeQuery.filterByExtensionType", performance.now() - tExtensionType, {
3702
+ before: beforeExtensionTypeCount,
3703
+ after: filteredProducts.length,
3704
+ extension_type
3705
+ });
3608
3706
  const tSort = performance.now();
3609
3707
  filteredProducts = filteredProducts.sort((a, b) => {
3610
3708
  const sortDiff = Number(b.sort) - Number(a.sort);
@@ -183,6 +183,7 @@ function buildProducts(order, locale, productMap) {
183
183
  currencySymbol,
184
184
  parentProduct
185
185
  });
186
+ const resolvedVariant = resolveProductVariantText({ product, parentProduct, locale });
186
187
  return {
187
188
  product_title: productTitle,
188
189
  product_quantity: quantity,
@@ -191,7 +192,7 @@ function buildProducts(order, locale, productMap) {
191
192
  total_original_price: formatMoney(new import_decimal.default(toMoneyNumber(originalPrice)).mul(quantity), currencySymbol),
192
193
  extension_list: Array.isArray(product.extension_list) ? product.extension_list : [],
193
194
  ...options.length ? { options } : {},
194
- ...product.variant ? { variant: getLocalizedValue(product.variant, locale) } : {},
195
+ ...resolvedVariant ? { variant: resolvedVariant } : {},
195
196
  ...Array.isArray(product.combinations) ? { combinations: product.combinations } : combinations.length ? { combinations } : {}
196
197
  };
197
198
  });
@@ -267,6 +268,82 @@ function resolveProductFromMap(productId, productMap) {
267
268
  return null;
268
269
  return productMap[productId] || productMap[String(productId)] || null;
269
270
  }
271
+ function resolveProductVariantText(params) {
272
+ const { product, parentProduct, locale } = params;
273
+ if (product.variant)
274
+ return getLocalizedValue(product.variant, locale);
275
+ if (!parentProduct)
276
+ return "";
277
+ const productVariantId = product.product_variant_id ?? product.variant_id;
278
+ if (!isNonZeroId(productVariantId))
279
+ return "";
280
+ const matchedVariant = normalizeArray(parentProduct.variant).find((variant) => isSameId(variant.id, productVariantId));
281
+ if (!matchedVariant)
282
+ return "";
283
+ const resolvedFromSkuKey = resolveVariantTextFromSkuKey({
284
+ skuKey: matchedVariant.sku_key,
285
+ parentProduct,
286
+ locale
287
+ });
288
+ if (resolvedFromSkuKey)
289
+ return resolvedFromSkuKey;
290
+ return resolveVariantTextFromNameMap({
291
+ nameMap: matchedVariant.name || matchedVariant.title,
292
+ parentProduct,
293
+ locale
294
+ });
295
+ }
296
+ function resolveVariantTextFromSkuKey(params) {
297
+ const skuKey = stringify(params.skuKey);
298
+ if (!skuKey)
299
+ return "";
300
+ return skuKey.split("_").map((item) => {
301
+ const [groupPositionId, itemPositionId] = item.split(":");
302
+ return resolveVariantTextItem({
303
+ parentProduct: params.parentProduct,
304
+ groupPositionId,
305
+ itemPositionId,
306
+ locale: params.locale
307
+ });
308
+ }).filter(Boolean).join(",");
309
+ }
310
+ function resolveVariantTextFromNameMap(params) {
311
+ if (!params.nameMap || typeof params.nameMap !== "object")
312
+ return "";
313
+ return Object.entries(params.nameMap).map(([groupPositionId, value]) => {
314
+ const group = resolveVariantGroup(params.parentProduct, groupPositionId);
315
+ if (!group)
316
+ return "";
317
+ const groupName = getLocalizedValue(group.name, params.locale);
318
+ const itemName = getLocalizedValue(value, params.locale);
319
+ if (!groupName || !itemName)
320
+ return "";
321
+ return `${groupName}:${itemName}`;
322
+ }).filter(Boolean).join(",");
323
+ }
324
+ function resolveVariantTextItem(params) {
325
+ const group = resolveVariantGroup(params.parentProduct, params.groupPositionId);
326
+ const item = resolveVariantItem(group, params.itemPositionId);
327
+ if (!group || !item)
328
+ return "";
329
+ const groupName = getLocalizedValue(group.name, params.locale);
330
+ const itemName = getLocalizedValue(item.name, params.locale);
331
+ if (!groupName || !itemName)
332
+ return "";
333
+ return `${groupName}:${itemName}`;
334
+ }
335
+ function resolveVariantGroup(parentProduct, groupPositionId) {
336
+ return normalizeArray(parentProduct.variant_group).find(
337
+ (group) => isSameId(group.position_id, groupPositionId) || isSameId(group.id, groupPositionId)
338
+ ) || null;
339
+ }
340
+ function resolveVariantItem(group, itemPositionId) {
341
+ if (!group)
342
+ return null;
343
+ return normalizeArray(group.variant_item).find(
344
+ (item) => isSameId(item.position_id, itemPositionId) || isSameId(item.id, itemPositionId)
345
+ ) || null;
346
+ }
270
347
  function getProductTitleSource(source, locale) {
271
348
  if (!source || typeof source !== "object")
272
349
  return "";
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
311
311
  date: string;
312
312
  status: string;
313
313
  week: string;
314
- weekNum: 0 | 2 | 1 | 6 | 3 | 4 | 5;
314
+ weekNum: 0 | 1 | 5 | 4 | 2 | 3 | 6;
315
315
  }[]>;
316
316
  submitTimeSlot(timeSlots: TimeSliceItem): void;
317
317
  private getScheduleDataByIds;
@@ -121,6 +121,13 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
121
121
  callback?: (result: any) => void;
122
122
  subscriberId?: string;
123
123
  }): Promise<any>;
124
+ /**
125
+ * 获取加时商品列表。
126
+ *
127
+ * @example
128
+ * const products = await bookingTicket.getAddTimeProducts({ schedule_date: '2026-06-16' });
129
+ */
130
+ getAddTimeProducts(params?: ILoadProductsParams): Promise<ProductData[]>;
124
131
  /**
125
132
  * 只读查询单商品详情:走 ProductList 报价查询,但不写 productCatalog、
126
133
  * 不 emit onProductsLoaded、不修改 BookingDate。
@@ -312,7 +319,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
312
319
  * 获取当前的客户搜索条件
313
320
  * @returns 当前搜索条件
314
321
  */
315
- getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
322
+ getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "skip" | "num">;
316
323
  /**
317
324
  * 获取客户列表状态(包含滚动加载相关状态)
318
325
  * @returns 客户状态
@@ -504,6 +511,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
504
511
  * ```
505
512
  */
506
513
  handleGlobalScanCode(code: string, bridge?: GlobalScanHostBridge): Promise<GlobalScanHandleResult>;
514
+ resolveBestAddTimePlan(addTimeProducts: any[], targetMinutes: number): any;
507
515
  /**
508
516
  * 销毁模块:先调用父类(销毁所有 store 内子模块 + emit destroy + super.destroy()),
509
517
  * 再清理 BookingTicket 自有资源(scan 监听 + scan 内存缓存)。