@pisell/pisellos 0.0.557 → 0.0.559

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 (63) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +3 -0
  3. package/dist/model/strategy/adapter/dataVariant/adapter.d.ts +49 -0
  4. package/dist/model/strategy/adapter/dataVariant/adapter.js +152 -0
  5. package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +87 -0
  6. package/dist/model/strategy/adapter/dataVariant/evaluator.js +755 -0
  7. package/dist/model/strategy/adapter/dataVariant/examples.d.ts +39 -0
  8. package/dist/model/strategy/adapter/dataVariant/examples.js +277 -0
  9. package/dist/model/strategy/adapter/dataVariant/index.d.ts +4 -0
  10. package/dist/model/strategy/adapter/dataVariant/index.js +4 -0
  11. package/dist/model/strategy/adapter/dataVariant/type.d.ts +146 -0
  12. package/dist/model/strategy/adapter/dataVariant/type.js +54 -0
  13. package/dist/model/strategy/adapter/index.d.ts +4 -0
  14. package/dist/model/strategy/adapter/index.js +5 -1
  15. package/dist/modules/Order/index.d.ts +1 -1
  16. package/dist/modules/ProductList/index.d.ts +2 -1
  17. package/dist/modules/ProductList/index.js +21 -11
  18. package/dist/solution/BookingByStep/index.d.ts +1 -1
  19. package/dist/solution/BookingTicket/index.d.ts +1 -1
  20. package/dist/solution/ScanOrder/index.d.ts +1 -1
  21. package/dist/solution/ScanOrder/index.js +33 -32
  22. package/dist/solution/VenueBooking/index.d.ts +22 -3
  23. package/dist/solution/VenueBooking/index.js +261 -167
  24. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +2 -2
  25. package/dist/solution/VenueBooking/utils/dateSummary.js +12 -25
  26. package/dist/solution/VenueBooking/utils/slotMerge.d.ts +0 -6
  27. package/dist/solution/VenueBooking/utils/slotMerge.js +3 -9
  28. package/dist/solution/VenueBooking/utils/smartPricing.d.ts +69 -0
  29. package/dist/solution/VenueBooking/utils/smartPricing.js +233 -0
  30. package/dist/solution/VenueBooking/utils/timeSlot.d.ts +2 -0
  31. package/dist/solution/VenueBooking/utils/timeSlot.js +9 -4
  32. package/lib/index.d.ts +1 -0
  33. package/lib/index.js +3 -0
  34. package/lib/model/strategy/adapter/dataVariant/adapter.d.ts +49 -0
  35. package/lib/model/strategy/adapter/dataVariant/adapter.js +139 -0
  36. package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +87 -0
  37. package/lib/model/strategy/adapter/dataVariant/evaluator.js +564 -0
  38. package/lib/model/strategy/adapter/dataVariant/examples.d.ts +39 -0
  39. package/lib/model/strategy/adapter/dataVariant/examples.js +293 -0
  40. package/lib/model/strategy/adapter/dataVariant/index.d.ts +4 -0
  41. package/lib/model/strategy/adapter/dataVariant/index.js +38 -0
  42. package/lib/model/strategy/adapter/dataVariant/type.d.ts +146 -0
  43. package/lib/model/strategy/adapter/dataVariant/type.js +31 -0
  44. package/lib/model/strategy/adapter/index.d.ts +4 -0
  45. package/lib/model/strategy/adapter/index.js +13 -2
  46. package/lib/modules/Order/index.d.ts +1 -1
  47. package/lib/modules/ProductList/index.d.ts +2 -1
  48. package/lib/modules/ProductList/index.js +45 -40
  49. package/lib/solution/BookingByStep/index.d.ts +1 -1
  50. package/lib/solution/BookingTicket/index.d.ts +1 -1
  51. package/lib/solution/ScanOrder/index.d.ts +1 -1
  52. package/lib/solution/ScanOrder/index.js +2 -1
  53. package/lib/solution/VenueBooking/index.d.ts +22 -3
  54. package/lib/solution/VenueBooking/index.js +152 -63
  55. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +2 -2
  56. package/lib/solution/VenueBooking/utils/dateSummary.js +5 -10
  57. package/lib/solution/VenueBooking/utils/slotMerge.d.ts +0 -6
  58. package/lib/solution/VenueBooking/utils/slotMerge.js +3 -4
  59. package/lib/solution/VenueBooking/utils/smartPricing.d.ts +69 -0
  60. package/lib/solution/VenueBooking/utils/smartPricing.js +180 -0
  61. package/lib/solution/VenueBooking/utils/timeSlot.d.ts +2 -0
  62. package/lib/solution/VenueBooking/utils/timeSlot.js +7 -3
  63. package/package.json +1 -1
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
326
326
  date: string;
327
327
  status: string;
328
328
  week: string;
329
- weekNum: 0 | 2 | 1 | 3 | 5 | 4 | 6;
329
+ weekNum: 0 | 1 | 2 | 3 | 4 | 5 | 6;
330
330
  }[]>;
331
331
  submitTimeSlot(timeSlots: TimeSliceItem): void;
332
332
  private getScheduleDataByIds;
@@ -131,7 +131,7 @@ export declare class BookingTicketImpl extends BaseModule implements Module {
131
131
  * 获取当前的客户搜索条件
132
132
  * @returns 当前搜索条件
133
133
  */
134
- getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "skip" | "num">;
134
+ getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
135
135
  /**
136
136
  * 获取客户列表状态(包含滚动加载相关状态)
137
137
  * @returns 客户状态
@@ -72,7 +72,7 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
72
72
  getTempOrder(): ScanOrderTempOrder | null;
73
73
  updateTempOrderNote(note: string): string;
74
74
  setPickupReferenceMode(mode: 'counter_pickup' | 'table_service'): {
75
- service_type: 'dine_in';
75
+ service_type: 'dine_in' | '';
76
76
  pickup_reference_mode: 'counter_pickup' | 'table_service';
77
77
  };
78
78
  setPickupRef(buzzer: string): string;
@@ -553,6 +553,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
553
553
  // 存储 UI 层选择的取餐方式到 tempOrder.metadata.shop_service_data
554
554
  // service_type 在扫码点餐场景固定为 dine_in
555
555
  setPickupReferenceMode(mode) {
556
+ var _a;
556
557
  this.logMethodStart("setPickupReferenceMode", { mode });
557
558
  try {
558
559
  if (!this.store.order)
@@ -562,7 +563,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
562
563
  ...tempOrder.metadata || {},
563
564
  shop_service_data: {
564
565
  ...(tempOrder.metadata || {}).shop_service_data || {},
565
- service_type: "dine_in",
566
+ service_type: ((_a = this.otherParams) == null ? void 0 : _a.businessCode) === "dine_in" ? "dine_in" : "",
566
567
  pickup_reference_mode: mode
567
568
  }
568
569
  };
@@ -3,6 +3,7 @@ import { BaseModule } from '../../modules/BaseModule';
3
3
  import { VenueBookingAddLogParams, VenueBookingSlotConfig, VenueDateSummaryItem, VenueSlotSelection, VenueTimeSlotGrid } from './types';
4
4
  import type { ScanOrderOrderProduct, ScanOrderOrderProductIdentity } from '../ScanOrder/types';
5
5
  import type { UpdateProductInOrderParams } from '../../modules/Order/types';
6
+ import type { ScheduleItem } from '../../modules/Schedule/types';
6
7
  import type { OpenDataAvailabilityResult } from '../../modules/OpenData';
7
8
  import type { ProductData } from '../../modules/Product/types';
8
9
  import { type CartItemSummary, type PaxInfo, type QuantityCheckResult, type QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
@@ -41,6 +42,10 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
41
42
  private productsLoaded;
42
43
  private loadOpenDataConfigInFlight;
43
44
  private static readonly OPEN_DATA_CACHE_TTL;
45
+ /** 按日期缓存 slot 智能定价 Map,避免同周重复 resolveProducts */
46
+ private slotPriceMapCache;
47
+ /** loadProducts 后缓存的全量商品(venue + addon),供分段算价复用 */
48
+ private smartPricingProductCatalog;
44
49
  private getLoggerContext;
45
50
  private safeStringify;
46
51
  private pickErrorMessage;
@@ -75,6 +80,21 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
75
80
  passed: boolean | null;
76
81
  failures: QuantityCheckResult[];
77
82
  };
83
+ /** 清除 slot 价格分段缓存(商品重载 / 登录后 customerId 变化时调用) */
84
+ private clearSlotPriceMapCache;
85
+ /** 读取当前登录 customerId */
86
+ private resolveCustomerIdForSmartPricing;
87
+ /** 读取 schedule 全量列表,供智能定价 schedule_match 使用 */
88
+ private getScheduleListForSmartPricing;
89
+ /** 构建智能定价上下文,对齐 OS Server buildProductFormatterContext */
90
+ private buildSmartPricingContext;
91
+ /** venue + addon 全量商品,供智能定价评估 */
92
+ private getAllProductsForSmartPricing;
93
+ private getSlotPriceMapCacheKey;
94
+ /**
95
+ * 按 schedule 分段构建 slot 价格 Map,带实例级缓存。
96
+ */
97
+ private buildSlotPriceMapForDate;
78
98
  loadAllProducts(): Promise<{
79
99
  venueProducts: ProductData[];
80
100
  addonProducts: ProductData[];
@@ -147,8 +167,7 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
147
167
  setSlotConfig(config: Partial<VenueBookingSlotConfig>): void;
148
168
  getSlotConfig(): VenueBookingSlotConfig;
149
169
  loadSchedules(): Promise<void>;
150
- private injectScheduleResolverToQuotation;
151
- getScheduleListByIds(ids: number[]): import("../../server").ScheduleItem[];
170
+ getScheduleListByIds(ids: number[]): ScheduleItem[];
152
171
  getTempOrder(): import("./types").ScanOrderTempOrder | null;
153
172
  updateTempOrderNote(note: string): string;
154
173
  updateTempOrderContactsInfo(contactsInfo: any[]): any[];
@@ -156,7 +175,7 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
156
175
  onCustomerLogin(params: {
157
176
  customerId: number;
158
177
  }): Promise<void>;
159
- private recalculateOrderPricesFromQuotation;
178
+ private recalculateOrderPricesFromSmartPricing;
160
179
  scanCode(code: string, customerId?: number): Promise<{
161
180
  isAvailable: boolean;
162
181
  discountList: import("../../modules/Discount").Discount[];
@@ -50,6 +50,7 @@ var import_resource = require("./utils/resource");
50
50
  var import_timeSlot = require("./utils/timeSlot");
51
51
  var import_dateSummary = require("./utils/dateSummary");
52
52
  var import_slotMerge = require("./utils/slotMerge");
53
+ var import_smartPricing = require("./utils/smartPricing");
53
54
  var import_utils3 = require("../../modules/Order/utils");
54
55
  var import_Order = require("../../modules/Order");
55
56
  var import_types4 = require("../RegisterAndLogin/types");
@@ -112,6 +113,10 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
112
113
  this.loadAllProductsInFlight = null;
113
114
  this.productsLoaded = false;
114
115
  this.loadOpenDataConfigInFlight = null;
116
+ /** 按日期缓存 slot 智能定价 Map,避免同周重复 resolveProducts */
117
+ this.slotPriceMapCache = /* @__PURE__ */ new Map();
118
+ /** loadProducts 后缓存的全量商品(venue + addon),供分段算价复用 */
119
+ this.smartPricingProductCatalog = [];
115
120
  }
116
121
  getLoggerContext() {
117
122
  return {
@@ -337,6 +342,8 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
337
342
  this.customerLoginRefreshIdInFlight = params.customerId;
338
343
  const refreshTask = (async () => {
339
344
  var _a;
345
+ this.clearSlotPriceMapCache();
346
+ this.recalculateOrderPricesFromSmartPricing();
340
347
  if (this.store.holder) {
341
348
  await this.store.holder.refreshAllFormRecords({
342
349
  customer_id: params.customerId,
@@ -348,7 +355,6 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
348
355
  channel: (_a = this.otherParams) == null ? void 0 : _a.channel
349
356
  });
350
357
  }
351
- this.recalculateOrderPricesFromQuotation();
352
358
  await this.store.order.loadDiscountConfig({
353
359
  customerId: params.customerId
354
360
  });
@@ -370,7 +376,7 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
370
376
  }
371
377
  }
372
378
  async initialize(core, options = {}) {
373
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
379
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
374
380
  this.logMethodStart("initialize");
375
381
  this.core = core;
376
382
  this.initializeOptions = options || {};
@@ -528,10 +534,6 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
528
534
  await this.loadRuntimeConfigs();
529
535
  if (this.store.schedule) {
530
536
  await this.store.schedule.loadAllSchedule();
531
- this.injectScheduleResolverToQuotation();
532
- (_o = this.store.quotation) == null ? void 0 : _o.loadQuotations({
533
- channel: (_n = this.otherParams) == null ? void 0 : _n.channel
534
- });
535
537
  }
536
538
  await this.refreshItemRuleQuantityLimits();
537
539
  this.store.status = "ready";
@@ -607,6 +609,81 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
607
609
  getCartValidation() {
608
610
  return this.store.cartValidation || { passed: null, failures: [] };
609
611
  }
612
+ /** 清除 slot 价格分段缓存(商品重载 / 登录后 customerId 变化时调用) */
613
+ clearSlotPriceMapCache() {
614
+ this.slotPriceMapCache.clear();
615
+ }
616
+ /** 读取当前登录 customerId */
617
+ resolveCustomerIdForSmartPricing() {
618
+ var _a, _b, _c;
619
+ try {
620
+ const userPlugin = (_a = this.core) == null ? void 0 : _a.getPlugin("user");
621
+ const customerId = Number((_c = (_b = userPlugin == null ? void 0 : userPlugin.get) == null ? void 0 : _b.call(userPlugin)) == null ? void 0 : _c.id);
622
+ return Number.isFinite(customerId) && customerId > 0 ? customerId : void 0;
623
+ } catch {
624
+ return void 0;
625
+ }
626
+ }
627
+ /** 读取 schedule 全量列表,供智能定价 schedule_match 使用 */
628
+ getScheduleListForSmartPricing() {
629
+ var _a;
630
+ const scheduleModule = this.store.schedule;
631
+ const list = (_a = scheduleModule == null ? void 0 : scheduleModule.store) == null ? void 0 : _a.scheduleList;
632
+ return Array.isArray(list) ? list : [];
633
+ }
634
+ /** 构建智能定价上下文,对齐 OS Server buildProductFormatterContext */
635
+ buildSmartPricingContext(customerId) {
636
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
637
+ const evaluator = (_b = (_a = this.core) == null ? void 0 : _a.context) == null ? void 0 : _b.dataVariantEvaluator;
638
+ return {
639
+ evaluator,
640
+ scheduleList: this.getScheduleListForSmartPricing(),
641
+ menuList: ((_c = this.otherParams) == null ? void 0 : _c.menuList) || ((_e = (_d = this.otherParams) == null ? void 0 : _d.openData) == null ? void 0 : _e.menuList) || [],
642
+ customerId: customerId ?? this.resolveCustomerIdForSmartPricing(),
643
+ channel: (_f = this.otherParams) == null ? void 0 : _f.channel,
644
+ businessCode: (_g = this.otherParams) == null ? void 0 : _g.businessCode,
645
+ orderType: ((_h = this.otherParams) == null ? void 0 : _h.orderType) || ((_i = this.otherParams) == null ? void 0 : _i.type),
646
+ strategy_context: (_j = this.otherParams) == null ? void 0 : _j.strategy_context
647
+ };
648
+ }
649
+ /** venue + addon 全量商品,供智能定价评估 */
650
+ getAllProductsForSmartPricing() {
651
+ if (this.smartPricingProductCatalog.length) {
652
+ return this.smartPricingProductCatalog;
653
+ }
654
+ const venueList = this.getVenueProducts();
655
+ const addonList = this.getAddonProductsList();
656
+ return [...venueList, ...addonList];
657
+ }
658
+ getSlotPriceMapCacheKey(date, context) {
659
+ return [
660
+ date,
661
+ context.customerId ?? "",
662
+ context.channel ?? "",
663
+ context.businessCode ?? ""
664
+ ].join("|");
665
+ }
666
+ /**
667
+ * 按 schedule 分段构建 slot 价格 Map,带实例级缓存。
668
+ */
669
+ buildSlotPriceMapForDate(date, config, productIds) {
670
+ const context = this.buildSmartPricingContext();
671
+ const cacheKey = this.getSlotPriceMapCacheKey(date, context);
672
+ const cached = this.slotPriceMapCache.get(cacheKey);
673
+ if (cached)
674
+ return cached;
675
+ const timeLabels = (0, import_timeSlot.generateTimeLabels)(config);
676
+ const slotPriceMap = (0, import_smartPricing.buildSlotPriceMapByScheduleSegments)({
677
+ products: this.getAllProductsForSmartPricing(),
678
+ productIds,
679
+ date,
680
+ timeLabels,
681
+ config,
682
+ context
683
+ });
684
+ this.slotPriceMapCache.set(cacheKey, slotPriceMap);
685
+ return slotPriceMap;
686
+ }
610
687
  // ─── 场地商品 & 附加商品 ───
611
688
  async loadAllProducts() {
612
689
  if (this.loadAllProductsInFlight)
@@ -635,9 +712,18 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
635
712
  menu_list_ids: menuListIds,
636
713
  cacheId: this.cacheId,
637
714
  schedule_date: (0, import_dayjs.default)().format("YYYY-MM-DD"),
638
- schedule_datetime: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
715
+ schedule_datetime: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss"),
716
+ with_extra: ["dataVariants"]
639
717
  });
640
- const list = Array.isArray(allProducts) ? allProducts : [];
718
+ const rawList = Array.isArray(allProducts) ? allProducts : [];
719
+ let list = rawList;
720
+ this.smartPricingProductCatalog = rawList.slice();
721
+ list = (0, import_smartPricing.formatProductsWithDataVariant)(
722
+ list,
723
+ this.buildSmartPricingContext(),
724
+ (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
725
+ );
726
+ this.clearSlotPriceMapCache();
641
727
  const venueList = list.filter((p) => p.duration != null);
642
728
  const addonList = list.filter((p) => p.duration == null);
643
729
  const venueStore = (_c = this.store.venueProducts) == null ? void 0 : _c.store;
@@ -822,29 +908,24 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
822
908
  config: this.baseSlotConfig,
823
909
  rawResources: this.store.rawResourceData,
824
910
  resourceProductMap: this.resourceProductMap,
825
- quotationModule: this.store.quotation,
826
- resolveConfig: (date) => this.resolveSlotConfigForDate(date)
911
+ resolveConfig: (date) => this.resolveSlotConfigForDate(date),
912
+ buildSlotPriceMap: (date, config, productIds) => this.buildSlotPriceMapForDate(date, config, productIds)
827
913
  });
828
914
  }
829
915
  getTimeSlotGrid(date) {
830
916
  const resolvedSlotConfig = this.syncOperatingHoursToSlotConfig(date);
831
- let quotationPriceMap;
832
- if (this.store.quotation) {
833
- const productIds = [
834
- ...new Set(
835
- [...this.resourceProductMap.values()].flat().map((m) => m.productId)
836
- )
837
- ];
838
- const timeLabels = (0, import_timeSlot.generateTimeLabels)(resolvedSlotConfig);
839
- const timePoints = timeLabels.map((label) => `${date} ${label}`);
840
- quotationPriceMap = this.store.quotation.buildProductPriceMap({ productIds, timePoints });
841
- }
917
+ const productIds = [
918
+ ...new Set(
919
+ [...this.resourceProductMap.values()].flat().map((m) => m.productId)
920
+ )
921
+ ];
922
+ const slotPriceMap = productIds.length ? this.buildSlotPriceMapForDate(date, resolvedSlotConfig, productIds) : void 0;
842
923
  return (0, import_timeSlot.buildTimeSlotGrid)({
843
924
  date,
844
925
  config: resolvedSlotConfig,
845
926
  rawResources: this.store.rawResourceData,
846
927
  resourceProductMap: this.resourceProductMap,
847
- quotationPriceMap
928
+ slotPriceMap
848
929
  });
849
930
  }
850
931
  // ─── 时间槽订单操作 ───
@@ -1130,8 +1211,7 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1130
1211
  booking_uid: bookingUuid,
1131
1212
  price_breakdown: (0, import_slotMerge.buildPriceBreakdown)({
1132
1213
  group,
1133
- productId: mapping.productId,
1134
- quotation: this.store.quotation
1214
+ productId: mapping.productId
1135
1215
  })
1136
1216
  },
1137
1217
  _origin: {
@@ -1229,20 +1309,12 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1229
1309
  if (!this.store.schedule)
1230
1310
  throw new Error("schedule 模块未初始化");
1231
1311
  await this.store.schedule.loadAllSchedule();
1232
- this.injectScheduleResolverToQuotation();
1233
1312
  this.logMethodSuccess("loadSchedules");
1234
1313
  } catch (error) {
1235
1314
  this.logMethodError("loadSchedules", error);
1236
1315
  throw error;
1237
1316
  }
1238
1317
  }
1239
- injectScheduleResolverToQuotation() {
1240
- if (this.store.quotation && this.store.schedule) {
1241
- this.store.quotation.setScheduleResolver(
1242
- (id) => this.store.schedule.getScheduleListByIds([id])[0]
1243
- );
1244
- }
1245
- }
1246
1318
  getScheduleListByIds(ids) {
1247
1319
  if (!this.store.schedule)
1248
1320
  return [];
@@ -1281,14 +1353,16 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1281
1353
  throw error;
1282
1354
  }
1283
1355
  }
1284
- recalculateOrderPricesFromQuotation() {
1356
+ recalculateOrderPricesFromSmartPricing() {
1285
1357
  var _a, _b;
1286
- if (!this.store.order || !this.store.quotation)
1358
+ if (!this.store.order)
1287
1359
  return;
1288
1360
  const tempOrder = this.store.order.getTempOrder();
1289
1361
  if (!((_a = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _a.length))
1290
1362
  return;
1291
1363
  const now = (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
1364
+ const catalog = this.getAllProductsForSmartPricing();
1365
+ const context = this.buildSmartPricingContext();
1292
1366
  for (const product of tempOrder.products) {
1293
1367
  if ((_b = product.metadata) == null ? void 0 : _b.venue_booking) {
1294
1368
  const mappings = this.resourceProductMap.get(product.metadata.resource_id);
@@ -1301,34 +1375,49 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1301
1375
  product,
1302
1376
  this.store.slotConfig.slotDurationMinutes
1303
1377
  );
1304
- const updatedSlots = slots.map((slot) => ({
1305
- ...slot,
1306
- productId: mapping.productId,
1307
- price: this.store.quotation.getPriceForProduct({
1378
+ const uniqueDates = [
1379
+ ...new Set(slots.map((slot) => (0, import_dayjs.default)(slot.startTime).format("YYYY-MM-DD")))
1380
+ ];
1381
+ const slotPriceMaps = /* @__PURE__ */ new Map();
1382
+ for (const slotDate of uniqueDates) {
1383
+ slotPriceMaps.set(
1384
+ slotDate,
1385
+ this.buildSlotPriceMapForDate(slotDate, this.store.slotConfig, [mapping.productId])
1386
+ );
1387
+ }
1388
+ const updatedSlots = slots.map((slot) => {
1389
+ const slotDate = (0, import_dayjs.default)(slot.startTime).format("YYYY-MM-DD");
1390
+ const slotPriceMap = slotPriceMaps.get(slotDate);
1391
+ return {
1392
+ ...slot,
1308
1393
  productId: mapping.productId,
1309
- datetime: slot.startTime
1310
- }) ?? mapping.price
1311
- }));
1394
+ price: slotPriceMap ? (0, import_smartPricing.getSlotPriceFromMap)({
1395
+ slotPriceMap,
1396
+ productId: mapping.productId,
1397
+ slotStartTime: slot.startTime,
1398
+ fallbackPrice: mapping.price
1399
+ }) : mapping.price
1400
+ };
1401
+ });
1312
1402
  const merged = (0, import_slotMerge.mergeConsecutiveSlots)(updatedSlots);
1313
1403
  if (merged.length === 1) {
1314
1404
  product.selling_price = merged[0].totalPrice;
1315
1405
  product.original_price = merged[0].totalPrice;
1316
1406
  product.metadata.price_breakdown = (0, import_slotMerge.buildPriceBreakdown)({
1317
1407
  group: merged[0],
1318
- productId: mapping.productId,
1319
- quotation: this.store.quotation
1408
+ productId: mapping.productId
1320
1409
  });
1321
1410
  }
1322
1411
  } else if (product.product_id != null) {
1323
- const quotationPrice = this.store.quotation.getPriceForProduct({
1324
- productId: product.product_id,
1325
- variantId: product.product_variant_id ?? void 0,
1326
- datetime: now
1412
+ const smartPrice = (0, import_smartPricing.getPriceForProductAtDatetime)({
1413
+ products: catalog,
1414
+ context,
1415
+ productId: Number(product.product_id),
1416
+ datetime: now,
1417
+ fallbackPrice: product.selling_price
1327
1418
  });
1328
- if (quotationPrice !== null) {
1329
- product.selling_price = quotationPrice;
1330
- product.original_price = quotationPrice;
1331
- }
1419
+ product.selling_price = smartPrice;
1420
+ product.original_price = smartPrice;
1332
1421
  }
1333
1422
  }
1334
1423
  }
@@ -1514,7 +1603,7 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1514
1603
  }
1515
1604
  }
1516
1605
  async addProductToOrder(product) {
1517
- var _a;
1606
+ var _a, _b;
1518
1607
  this.logMethodStart("addProductToOrder", {
1519
1608
  product_id: product.product_id,
1520
1609
  product_variant_id: product.product_variant_id
@@ -1522,18 +1611,18 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1522
1611
  try {
1523
1612
  if (!this.store.order)
1524
1613
  throw new Error("order 模块未初始化");
1525
- if (!((_a = product.metadata) == null ? void 0 : _a.venue_booking) && this.store.quotation && product.product_id != null) {
1526
- const quotationPrice = this.store.quotation.getPriceForProduct({
1527
- productId: product.product_id,
1528
- variantId: product.product_variant_id ?? void 0,
1529
- datetime: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
1614
+ if (!((_a = product.metadata) == null ? void 0 : _a.venue_booking) && product.product_id != null) {
1615
+ const smartPrice = (0, import_smartPricing.getPriceForProductAtDatetime)({
1616
+ products: this.getAllProductsForSmartPricing(),
1617
+ context: this.buildSmartPricingContext(),
1618
+ productId: Number(product.product_id),
1619
+ datetime: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss"),
1620
+ fallbackPrice: product.selling_price
1530
1621
  });
1531
- if (quotationPrice !== null) {
1532
- product.selling_price = quotationPrice;
1533
- product.original_price = quotationPrice;
1534
- } else if (product.selling_price != null) {
1535
- product.original_price = product.selling_price;
1536
- }
1622
+ product.selling_price = smartPrice;
1623
+ product.original_price = smartPrice;
1624
+ } else if (product.selling_price != null && !((_b = product.metadata) == null ? void 0 : _b.venue_booking)) {
1625
+ product.original_price = product.selling_price;
1537
1626
  }
1538
1627
  const products = await this.store.order.addProductToOrder(product);
1539
1628
  await this.refreshItemRuleQuantityLimits();
@@ -1,11 +1,11 @@
1
1
  import type { VenueBookingSlotConfig, VenueResourceRawData, VenueDateSummaryItem, ResourceProductMapping } from '../types';
2
- import type { QuotationModule } from '../../../modules/Quotation';
3
2
  export declare function buildDateRangeSummary(params: {
4
3
  startDate: string;
5
4
  endDate: string;
6
5
  config: VenueBookingSlotConfig;
7
6
  rawResources: VenueResourceRawData[];
8
7
  resourceProductMap: Map<number | string, ResourceProductMapping[]>;
9
- quotationModule?: QuotationModule;
10
8
  resolveConfig?: (date: string) => VenueBookingSlotConfig;
9
+ /** 按日期构建 slot 智能定价 Map */
10
+ buildSlotPriceMap?: (date: string, config: VenueBookingSlotConfig, productIds: number[]) => Map<string, string | null>;
11
11
  }): VenueDateSummaryItem[];
@@ -41,28 +41,23 @@ function buildDateRangeSummary(params) {
41
41
  config,
42
42
  rawResources,
43
43
  resourceProductMap,
44
- quotationModule,
45
- resolveConfig
44
+ resolveConfig,
45
+ buildSlotPriceMap
46
46
  } = params;
47
47
  const result = [];
48
- const productIds = quotationModule ? [...new Set([...resourceProductMap.values()].flat().map((m) => m.productId))] : [];
48
+ const productIds = buildSlotPriceMap ? [...new Set([...resourceProductMap.values()].flat().map((m) => m.productId))] : [];
49
49
  let cursor = (0, import_dayjs.default)(startDate);
50
50
  const end = (0, import_dayjs.default)(endDate);
51
51
  while (!cursor.isAfter(end)) {
52
52
  const date = cursor.format("YYYY-MM-DD");
53
53
  const effectiveConfig = (resolveConfig == null ? void 0 : resolveConfig(date)) || config;
54
- let quotationPriceMap;
55
- if (quotationModule && productIds.length) {
56
- const timeLabels = (0, import_timeSlot.generateTimeLabels)(effectiveConfig);
57
- const timePoints = timeLabels.map((label) => `${date} ${label}`);
58
- quotationPriceMap = quotationModule.buildProductPriceMap({ productIds, timePoints });
59
- }
54
+ const slotPriceMap = buildSlotPriceMap && productIds.length ? buildSlotPriceMap(date, effectiveConfig, productIds) : void 0;
60
55
  const grid = (0, import_timeSlot.buildTimeSlotGrid)({
61
56
  date,
62
57
  config: effectiveConfig,
63
58
  rawResources,
64
59
  resourceProductMap,
65
- quotationPriceMap
60
+ slotPriceMap
66
61
  });
67
62
  let totalSlots = 0;
68
63
  let availableSlots = 0;
@@ -5,12 +5,6 @@ export declare function mergeConsecutiveSlots(slots: VenueSlotSelection[]): Merg
5
5
  export declare function buildPriceBreakdown(params: {
6
6
  group: MergedSlotGroup;
7
7
  productId: number;
8
- quotation?: {
9
- getQuotationShelfId: (p: {
10
- productId: number;
11
- datetime: string;
12
- }) => number;
13
- };
14
8
  }): PriceBreakdownEntry[];
15
9
  export interface BuildVenueBookingParams {
16
10
  group: MergedSlotGroup;
@@ -82,17 +82,16 @@ function mergeConsecutiveSlots(slots) {
82
82
  return groups;
83
83
  }
84
84
  function buildPriceBreakdown(params) {
85
- const { group, productId, quotation } = params;
85
+ const { group } = params;
86
86
  if (!group.slots.length)
87
87
  return [];
88
88
  const entries = [];
89
89
  for (const slot of group.slots) {
90
90
  const unitPrice = Number(slot.price || "0");
91
- const shelfId = quotation ? quotation.getQuotationShelfId({ productId, datetime: slot.startTime }) : 0;
92
91
  const startHm = (0, import_dayjs.default)(slot.startTime, "YYYY-MM-DD HH:mm").format("YYYY-MM-DD HH:mm");
93
92
  const endHm = (0, import_dayjs.default)(slot.endTime, "YYYY-MM-DD HH:mm").format("YYYY-MM-DD HH:mm");
94
93
  const last = entries[entries.length - 1];
95
- if (last && last.unit_price === unitPrice && last.quotation_shelf_id === shelfId && last.end_time === startHm) {
94
+ if (last && last.unit_price === unitPrice && last.quotation_shelf_id === 0 && last.end_time === startHm) {
96
95
  last.end_time = endHm;
97
96
  last.quantity += 1;
98
97
  } else {
@@ -100,7 +99,7 @@ function buildPriceBreakdown(params) {
100
99
  start_time: startHm,
101
100
  end_time: endHm,
102
101
  unit_price: unitPrice,
103
- quotation_shelf_id: shelfId,
102
+ quotation_shelf_id: 0,
104
103
  quantity: 1
105
104
  });
106
105
  }
@@ -0,0 +1,69 @@
1
+ import type { ProductData } from '../../../modules/Product/types';
2
+ import type { ScheduleItem } from '../../../modules/Schedule/types';
3
+ import type { DataVariantBusinessData, DataVariantMenu, DataVariantProduct } from '../../../model/strategy/adapter/dataVariant/type';
4
+ import type { DataVariantEvaluator } from '../../../model/strategy/adapter/dataVariant/evaluator';
5
+ import type { StrategyConfig } from '../../../model/strategy/type';
6
+ import type { VenueBookingSlotConfig } from '../types';
7
+ /** VenueBooking 智能定价运行时上下文 */
8
+ export interface VenueBookingSmartPricingContext {
9
+ evaluator?: DataVariantEvaluator | null;
10
+ scheduleList?: ScheduleItem[];
11
+ menuList?: DataVariantMenu[];
12
+ customerId?: number | string;
13
+ channel?: string;
14
+ businessCode?: string;
15
+ orderType?: string;
16
+ strategy_context?: Record<string, any>;
17
+ strategyConfigs?: StrategyConfig[];
18
+ }
19
+ /** 从商品上读取展示/算价用的 price 字段 */
20
+ export declare function extractProductPrice(product: DataVariantProduct): string | null;
21
+ /** 组装 DataVariant 评估入参,对齐 OS Server buildProductFormatterContext 语义 */
22
+ export declare function buildDataVariantBusinessData(products: ProductData[], context: VenueBookingSmartPricingContext, scheduleDateTime: string): DataVariantBusinessData;
23
+ /**
24
+ * 对商品列表执行一次智能定价格式化(loadProducts 后使用)。
25
+ * evaluator 未注入时原样返回并打 warning。
26
+ */
27
+ export declare function formatProductsWithDataVariant(products: ProductData[], context: VenueBookingSmartPricingContext, scheduleDateTime?: string): ProductData[];
28
+ /**
29
+ * 根据 schedule_time_points 与营业开始时间,构造当天需要评估的 datetime 列表(升序)。
30
+ * 跨日营业时,早于营业开始小时的时间点归到次日。
31
+ */
32
+ export declare function buildEvaluationDatetimes(params: {
33
+ date: string;
34
+ config: VenueBookingSlotConfig;
35
+ scheduleTimePoints: string[];
36
+ }): string[];
37
+ /** 找到 slot 时间所属分段的评估 datetime(max(evalDt <= slotDt)) */
38
+ export declare function findSegmentEvalDatetime(slotDatetime: string, evalDatetimes: string[]): string;
39
+ /** 将 slot 标签转为与 timeSlot 网格一致的 slotStart 字符串 */
40
+ export declare function buildSlotStartDatetime(date: string, label: string, config: VenueBookingSlotConfig): string;
41
+ /**
42
+ * 按 schedule 分段批量 resolveProducts,输出与 quotation 相同 key 格式的 slot 价格 Map。
43
+ * key: `${productId}:${slotStart}`,value: price | null
44
+ */
45
+ export declare function buildSlotPriceMapByScheduleSegments(params: {
46
+ products: ProductData[];
47
+ productIds: number[];
48
+ date: string;
49
+ timeLabels: string[];
50
+ config: VenueBookingSlotConfig;
51
+ context: VenueBookingSmartPricingContext;
52
+ }): Map<string, string | null>;
53
+ /**
54
+ * 指定商品在某一 datetime 的智能定价(addon / 单点重算用)。
55
+ */
56
+ export declare function getPriceForProductAtDatetime(params: {
57
+ products: ProductData[];
58
+ context: VenueBookingSmartPricingContext;
59
+ productId: number;
60
+ datetime: string;
61
+ fallbackPrice?: string;
62
+ }): string;
63
+ /** 从 slot 价格 Map 读取单价,找不到则回退 fallback */
64
+ export declare function getSlotPriceFromMap(params: {
65
+ slotPriceMap: Map<string, string | null>;
66
+ productId: number;
67
+ slotStartTime: string;
68
+ fallbackPrice?: string;
69
+ }): string;