@pisell/pisellos 2.1.163 → 2.1.164

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.
@@ -310,7 +310,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
310
310
  date: string;
311
311
  status: string;
312
312
  week: string;
313
- weekNum: 0 | 1 | 5 | 4 | 2 | 3 | 6;
313
+ weekNum: 0 | 2 | 1 | 5 | 4 | 3 | 6;
314
314
  }[]>;
315
315
  submitTimeSlot(timeSlots: TimeSliceItem): void;
316
316
  private getScheduleDataByIds;
@@ -329,7 +329,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
329
329
  count: number;
330
330
  left: number;
331
331
  summaryCount: number;
332
- status: "sold_out" | "lots_of_space" | "filling_up_fast";
332
+ status: "lots_of_space" | "filling_up_fast" | "sold_out";
333
333
  }[];
334
334
  /**
335
335
  * 找到多个资源的公共可用时间段
@@ -37,6 +37,8 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
37
37
  private loginEffectDisposers;
38
38
  private customerLoginRefreshInFlight;
39
39
  private customerLoginRefreshIdInFlight;
40
+ /** 最近一次确认登录的客户;登录事件与 user 插件更新之间可能存在时序差。 */
41
+ private smartPricingCustomerId;
40
42
  private loadAllProductsInFlight;
41
43
  private productsLoaded;
42
44
  private loadOpenDataConfigInFlight;
@@ -45,6 +47,7 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
45
47
  private slotPriceMapCache;
46
48
  /** loadProducts 后缓存的全量商品(venue + addon),供分段算价复用 */
47
49
  private smartPricingProductCatalog;
50
+ private static readonly PISELL1_LOGIN_SUCCESS;
48
51
  private getLoggerContext;
49
52
  private safeStringify;
50
53
  private pickErrorMessage;
@@ -170,6 +173,11 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
170
173
  customerId: number;
171
174
  }): Promise<void>;
172
175
  private recalculateOrderPricesFromSmartPricing;
176
+ /**
177
+ * DataVariant 重算价格后,同步刷新订单展示、Rules 与 Summary 共用的价格口径。
178
+ * Rules 会在本轮结束后根据当前客户的 discountList 重新写入实际折扣。
179
+ */
180
+ private resetProductPriceForSmartPricing;
173
181
  scanCode(code: string, customerId?: number): Promise<{
174
182
  isAvailable: boolean;
175
183
  discountList: import("../../modules/Discount").Discount[];
@@ -184,6 +192,15 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
184
192
  discountId: number;
185
193
  isSelected: boolean;
186
194
  }): Promise<import("../../modules/Discount").Discount[]>;
195
+ /**
196
+ * 统一 VenueBooking 折扣后的订单行价。
197
+ *
198
+ * Rules 的 `discount_list.amount` 是已经按适用规则计算出的每件优惠额;它是这里唯一
199
+ * 的折扣金额来源。使用智能定价写入的 source_product_price 减去该金额,再同步
200
+ * selling_price 与 Summary 使用的 main_product_selling_price,避免 UI 的购物车行价、
201
+ * 小计和提交订单各自读取到不同的价格字段。
202
+ */
203
+ private normalizeDiscountedOrderPrices;
187
204
  addNewOrder(): Promise<import("./types").ScanOrderTempOrder>;
188
205
  getOrderProducts(): ScanOrderOrderProduct[];
189
206
  getSummary(): Promise<import("./types").ScanOrderSummary>;
@@ -99,6 +99,8 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
99
99
  _defineProperty(_assertThisInitialized(_this), "loginEffectDisposers", []);
100
100
  _defineProperty(_assertThisInitialized(_this), "customerLoginRefreshInFlight", null);
101
101
  _defineProperty(_assertThisInitialized(_this), "customerLoginRefreshIdInFlight", null);
102
+ /** 最近一次确认登录的客户;登录事件与 user 插件更新之间可能存在时序差。 */
103
+ _defineProperty(_assertThisInitialized(_this), "smartPricingCustomerId", void 0);
102
104
  _defineProperty(_assertThisInitialized(_this), "loadAllProductsInFlight", null);
103
105
  _defineProperty(_assertThisInitialized(_this), "productsLoaded", false);
104
106
  _defineProperty(_assertThisInitialized(_this), "loadOpenDataConfigInFlight", null);
@@ -326,16 +328,9 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
326
328
  }, {
327
329
  key: "registerCustomerLoginListeners",
328
330
  value: function registerCustomerLoginListeners() {
329
- var _this$core2,
330
- _this$core3,
331
- _accountModule$getCur,
332
- _accountModule$getAcc,
333
- _this2 = this;
331
+ var _this2 = this;
334
332
  this.clearLoginEffectListeners();
335
- var accountModule = (_this$core2 = this.core) === null || _this$core2 === void 0 ? void 0 : _this$core2.getModule('account');
336
- var registerAndLoginModule = (_this$core3 = this.core) === null || _this$core3 === void 0 ? void 0 : _this$core3.getModule('registerAndLogin');
337
- var currentAccount = (accountModule === null || accountModule === void 0 || (_accountModule$getCur = accountModule.getCurrentAccount) === null || _accountModule$getCur === void 0 ? void 0 : _accountModule$getCur.call(accountModule)) || (accountModule === null || accountModule === void 0 || (_accountModule$getAcc = accountModule.getAccount) === null || _accountModule$getAcc === void 0 ? void 0 : _accountModule$getAcc.call(accountModule)) || null;
338
- var createHandleLogin = function createHandleLogin(eventName) {
333
+ var createHandleLogin = function createHandleLogin() {
339
334
  return /*#__PURE__*/function () {
340
335
  var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(payload) {
341
336
  var customerId;
@@ -364,8 +359,9 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
364
359
  };
365
360
  }();
366
361
  };
367
- this.registerLoginEffect(AccountHooks.OnLogin, createHandleLogin(AccountHooks.OnLogin));
368
- this.registerLoginEffect(RegisterAndLoginHooks.onLoginSuccess, createHandleLogin(RegisterAndLoginHooks.onLoginSuccess));
362
+ this.registerLoginEffect(VenueBookingImpl.PISELL1_LOGIN_SUCCESS, createHandleLogin());
363
+ this.registerLoginEffect(AccountHooks.OnLogin, createHandleLogin());
364
+ this.registerLoginEffect(RegisterAndLoginHooks.onLoginSuccess, createHandleLogin());
369
365
  }
370
366
  }, {
371
367
  key: "refreshOrderMarketingAfterLogin",
@@ -400,28 +396,40 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
400
396
  case 9:
401
397
  this.customerLoginRefreshIdInFlight = params.customerId;
402
398
  refreshTask = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4() {
399
+ var _this3$core, _this3$core$emit;
403
400
  return _regeneratorRuntime().wrap(function _callee4$(_context4) {
404
401
  while (1) switch (_context4.prev = _context4.next) {
405
402
  case 0:
406
- _context4.next = 2;
403
+ // 用户插件可能晚于登录 effect 更新;以已确认的登录 payload 作为本次及后续网格算价的身份来源。
404
+ _this3.smartPricingCustomerId = params.customerId;
405
+ _context4.next = 3;
407
406
  return _this3.store.order.loadDiscountConfig({
408
407
  customerId: params.customerId
409
408
  });
410
- case 2:
409
+ case 3:
411
410
  _this3.clearSlotPriceMapCache();
412
411
  _this3.recalculateOrderPricesFromSmartPricing();
413
- _context4.next = 6;
412
+ // loadDiscountConfig 会按登录前的订单价格预计算一次券;智能价更新后必须用新的
413
+ // source/main 价格字段重新套券,否则购物车行价与 Summary 会使用两套基数。
414
+ _this3.store.order.applyDiscount();
415
+ _this3.normalizeDiscountedOrderPrices(_this3.store.order.getDiscountList());
416
+ _context4.next = 9;
414
417
  return _this3.store.order.recalculateSummary({
415
418
  createIfMissing: true
416
419
  });
417
- case 6:
420
+ case 9:
418
421
  _this3.store.order.persistTempOrder();
419
- _context4.next = 9;
422
+ _context4.next = 12;
420
423
  return _this3.refreshItemRuleQuantityLimits();
421
- case 9:
422
- _context4.next = 11;
424
+ case 12:
425
+ _context4.next = 14;
423
426
  return _this3.refreshCartValidationPassed();
424
- case 11:
427
+ case 14:
428
+ _context4.next = 16;
429
+ return (_this3$core = _this3.core) === null || _this3$core === void 0 || (_this3$core = _this3$core.effects) === null || _this3$core === void 0 || (_this3$core$emit = _this3$core.emit) === null || _this3$core$emit === void 0 ? void 0 : _this3$core$emit.call(_this3$core, VenueBookingHooks.onSmartPricingUpdated, {
430
+ customerId: params.customerId
431
+ });
432
+ case 16:
425
433
  case "end":
426
434
  return _context4.stop();
427
435
  }
@@ -487,6 +495,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
487
495
  this.core = core;
488
496
  this.initializeOptions = options || {};
489
497
  this.store = _objectSpread(_objectSpread({}, this.store), options.store);
498
+ this.smartPricingCustomerId = undefined;
490
499
  this.store.entryContext = ((_options$otherParams = options.otherParams) === null || _options$otherParams === void 0 ? void 0 : _options$otherParams.entryContext) || this.store.entryContext;
491
500
  this.store.status = 'initializing';
492
501
  this.store.error = null;
@@ -507,19 +516,19 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
507
516
  this.window = core.getPlugin('window');
508
517
  this.request = core.getPlugin('request');
509
518
  if (this.window) {
510
- _context6.next = 24;
519
+ _context6.next = 25;
511
520
  break;
512
521
  }
513
522
  this.logMethodError('initialize', 'window plugin missing');
514
523
  throw new Error('venueBooking解决方案需要 window 插件支持');
515
- case 24:
524
+ case 25:
516
525
  if (this.request) {
517
- _context6.next = 27;
526
+ _context6.next = 28;
518
527
  break;
519
528
  }
520
529
  this.logMethodError('initialize', 'request plugin missing');
521
530
  throw new Error('venueBooking解决方案需要 request 插件支持');
522
- case 27:
531
+ case 28:
523
532
  // 注册基础模块(order, salesSummary, products, logger)
524
533
  baseModules = ['scanOrderLogger', 'products', 'order', 'salesSummary'];
525
534
  baseModules.forEach(function (step) {
@@ -616,41 +625,41 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
616
625
  }
617
626
  this.registerCustomerLoginListeners();
618
627
  console.log('[VenueBooking] 初始化开始');
619
- _context6.prev = 50;
620
- _context6.next = 53;
628
+ _context6.prev = 51;
629
+ _context6.next = 54;
621
630
  return (_this$store$order = this.store.order) === null || _this$store$order === void 0 ? void 0 : _this$store$order.recalculateSummary({
622
631
  createIfMissing: false
623
632
  });
624
- case 53:
633
+ case 54:
625
634
  (_this$store$order2 = this.store.order) === null || _this$store$order2 === void 0 || _this$store$order2.persistTempOrder();
626
- _context6.next = 56;
635
+ _context6.next = 57;
627
636
  return this.loadRuntimeConfigs();
628
- case 56:
637
+ case 57:
629
638
  if (!this.store.schedule) {
630
- _context6.next = 59;
639
+ _context6.next = 60;
631
640
  break;
632
641
  }
633
- _context6.next = 59;
642
+ _context6.next = 60;
634
643
  return this.store.schedule.loadAllSchedule();
635
- case 59:
636
- _context6.next = 61;
644
+ case 60:
645
+ _context6.next = 62;
637
646
  return this.refreshItemRuleQuantityLimits();
638
- case 61:
647
+ case 62:
639
648
  this.store.status = 'ready';
640
649
  console.log('[VenueBooking] 初始化完成');
641
- _context6.next = 65;
650
+ _context6.next = 66;
642
651
  return this.core.effects.emit(VenueBookingHooks.onInited, {
643
652
  status: this.store.status
644
653
  });
645
- case 65:
654
+ case 66:
646
655
  this.logMethodSuccess('initialize', {
647
656
  status: this.store.status
648
657
  });
649
- _context6.next = 75;
658
+ _context6.next = 76;
650
659
  break;
651
- case 68:
652
- _context6.prev = 68;
653
- _context6.t0 = _context6["catch"](50);
660
+ case 69:
661
+ _context6.prev = 69;
662
+ _context6.t0 = _context6["catch"](51);
654
663
  this.store.status = 'error';
655
664
  this.store.error = _context6.t0 instanceof Error ? _context6.t0.message : '初始化失败';
656
665
  console.error('[VenueBooking] 初始化失败', _context6.t0);
@@ -658,11 +667,11 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
658
667
  status: this.store.status
659
668
  });
660
669
  throw _context6.t0;
661
- case 75:
670
+ case 76:
662
671
  case "end":
663
672
  return _context6.stop();
664
673
  }
665
- }, _callee6, this, [[50, 68]]);
674
+ }, _callee6, this, [[51, 69]]);
666
675
  }));
667
676
  function initialize(_x5) {
668
677
  return _initialize.apply(this, arguments);
@@ -814,9 +823,10 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
814
823
  }, {
815
824
  key: "resolveCustomerIdForSmartPricing",
816
825
  value: function resolveCustomerIdForSmartPricing() {
826
+ if (this.smartPricingCustomerId) return this.smartPricingCustomerId;
817
827
  try {
818
- var _this$core4, _userPlugin$get;
819
- var userPlugin = (_this$core4 = this.core) === null || _this$core4 === void 0 ? void 0 : _this$core4.getPlugin('user');
828
+ var _this$core2, _userPlugin$get;
829
+ var userPlugin = (_this$core2 = this.core) === null || _this$core2 === void 0 ? void 0 : _this$core2.getPlugin('user');
820
830
  var customerId = Number(userPlugin === null || userPlugin === void 0 || (_userPlugin$get = userPlugin.get) === null || _userPlugin$get === void 0 || (_userPlugin$get = _userPlugin$get.call(userPlugin)) === null || _userPlugin$get === void 0 ? void 0 : _userPlugin$get.id);
821
831
  return Number.isFinite(customerId) && customerId > 0 ? customerId : undefined;
822
832
  } catch (_unused2) {
@@ -853,8 +863,8 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
853
863
  }, {
854
864
  key: "buildSmartPricingContext",
855
865
  value: function buildSmartPricingContext(customerId) {
856
- var _this$core5, _this$otherParams10, _this$otherParams11, _this$otherParams12, _this$otherParams13, _this$otherParams14, _this$otherParams15, _this$otherParams16;
857
- var evaluator = (_this$core5 = this.core) === null || _this$core5 === void 0 || (_this$core5 = _this$core5.context) === null || _this$core5 === void 0 ? void 0 : _this$core5.dataVariantEvaluator;
866
+ var _this$core3, _this$otherParams10, _this$otherParams11, _this$otherParams12, _this$otherParams13, _this$otherParams14, _this$otherParams15, _this$otherParams16;
867
+ var evaluator = (_this$core3 = this.core) === null || _this$core3 === void 0 || (_this$core3 = _this$core3.context) === null || _this$core3 === void 0 ? void 0 : _this$core3.dataVariantEvaluator;
858
868
  return {
859
869
  evaluator: evaluator,
860
870
  scheduleList: this.getScheduleListForSmartPricing(),
@@ -2076,11 +2086,13 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2076
2086
  });
2077
2087
  var merged = mergeConsecutiveSlots(updatedSlots);
2078
2088
  if (merged.length === 1) {
2079
- product.selling_price = merged[0].totalPrice;
2080
- product.original_price = merged[0].totalPrice;
2081
- product.metadata.price_breakdown = buildPriceBreakdown({
2082
- group: merged[0],
2083
- productId: mapping.productId
2089
+ _this9.resetProductPriceForSmartPricing({
2090
+ product: product,
2091
+ price: merged[0].totalPrice,
2092
+ priceBreakdown: buildPriceBreakdown({
2093
+ group: merged[0],
2094
+ productId: mapping.productId
2095
+ })
2084
2096
  });
2085
2097
  }
2086
2098
  } else if (product.product_id != null) {
@@ -2091,8 +2103,10 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2091
2103
  datetime: now,
2092
2104
  fallbackPrice: product.selling_price
2093
2105
  });
2094
- product.selling_price = smartPrice;
2095
- product.original_price = smartPrice;
2106
+ _this9.resetProductPriceForSmartPricing({
2107
+ product: product,
2108
+ price: smartPrice
2109
+ });
2096
2110
  }
2097
2111
  },
2098
2112
  _ret;
@@ -2106,6 +2120,30 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2106
2120
  _iterator12.f();
2107
2121
  }
2108
2122
  }
2123
+
2124
+ /**
2125
+ * DataVariant 重算价格后,同步刷新订单展示、Rules 与 Summary 共用的价格口径。
2126
+ * Rules 会在本轮结束后根据当前客户的 discountList 重新写入实际折扣。
2127
+ */
2128
+ }, {
2129
+ key: "resetProductPriceForSmartPricing",
2130
+ value: function resetProductPriceForSmartPricing(params) {
2131
+ var product = params.product,
2132
+ price = params.price,
2133
+ priceBreakdown = params.priceBreakdown;
2134
+ var metadata = product.metadata || {};
2135
+ product.selling_price = price;
2136
+ product.original_price = price;
2137
+ product.discount_list = [];
2138
+ product.metadata = _objectSpread(_objectSpread(_objectSpread({}, metadata), priceBreakdown ? {
2139
+ price_breakdown: priceBreakdown
2140
+ } : {}), {}, {
2141
+ source_product_price: price,
2142
+ main_product_original_price: price,
2143
+ main_product_selling_price: price,
2144
+ price_schema_version: 2
2145
+ });
2146
+ }
2109
2147
  }, {
2110
2148
  key: "scanCode",
2111
2149
  value: function () {
@@ -2171,7 +2209,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2171
2209
  key: "setDiscountSelected",
2172
2210
  value: (function () {
2173
2211
  var _setDiscountSelected = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee21(params) {
2174
- var _tempOrder$holder, _this$store$order$get, _this$store$order$get2, list, beforeTarget, updated, updatedTarget, tempOrder, orderStore, discountModule, rulesModule, holders, nextDiscountList, _tempOrder$holder2, result, beforeSelectedIds, _iterator14, _step14, d, selectedResourceIds, _iterator15, _step15, _product$_origin, _product$metadata$sou, _product$metadata3, _product$metadata4, _product$original_pri, product, totalPerUnitDiscount, optionSum, sourcePrice, newSourceSellingPrice, newMainSellingPrice, afterApplyTarget, finalSummary, finalProduct, finalTarget;
2212
+ var _tempOrder$holder, _this$store$order$get, _this$store$order$get2, list, beforeTarget, updated, updatedTarget, tempOrder, orderStore, discountModule, rulesModule, holders, nextDiscountList, _tempOrder$holder2, result, beforeSelectedIds, _iterator14, _step14, d, afterApplyTarget, finalSummary, finalProduct, finalTarget;
2175
2213
  return _regeneratorRuntime().wrap(function _callee21$(_context21) {
2176
2214
  while (1) switch (_context21.prev = _context21.next) {
2177
2215
  case 0:
@@ -2247,83 +2285,22 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2247
2285
  }
2248
2286
  }
2249
2287
  }
2250
- selectedResourceIds = new Set(nextDiscountList.filter(function (d) {
2251
- return d.isSelected;
2252
- }).map(function (d) {
2253
- return d.id;
2254
- })); // 无条件归一化:不论 Rules 是否清空 discount_list、长度是否变化,
2255
- // 都以 original_price - Σ (当前选中 discount_list.amount) 重算 selling_price。
2256
- // 目的:避免 unselect 后 selling_price 残留、reselect 时把残留价带进下一轮 Rules 造成双折扣。
2257
- // 手动改价商品(_origin.isManualDiscount=true)不参与券流程归一化,保留手工价。
2258
- _iterator15 = _createForOfIteratorHelper(tempOrder.products);
2259
- _context21.prev = 19;
2260
- _iterator15.s();
2261
- case 21:
2262
- if ((_step15 = _iterator15.n()).done) {
2263
- _context21.next = 35;
2264
- break;
2265
- }
2266
- product = _step15.value;
2267
- if (!((_product$_origin = product._origin) !== null && _product$_origin !== void 0 && _product$_origin.isManualDiscount)) {
2268
- _context21.next = 25;
2269
- break;
2270
- }
2271
- return _context21.abrupt("continue", 33);
2272
- case 25:
2273
- // 1. 把 product.discount_list 和当前选中的 discount 对齐(剔除已取消的券)
2274
- product.discount_list = (product.discount_list || []).filter(function (pd) {
2275
- var _pd$discount$resource, _pd$discount;
2276
- var rid = (_pd$discount$resource = (_pd$discount = pd.discount) === null || _pd$discount === void 0 ? void 0 : _pd$discount.resource_id) !== null && _pd$discount$resource !== void 0 ? _pd$discount$resource : pd.id;
2277
- return rid != null && selectedResourceIds.has(rid);
2278
- });
2279
-
2280
- // 2. 以 source_product_price 为券作用基准:券作用于 source(不含 option),
2281
- // 再把 option 加回得到含 option 的 main_product_selling_price,最后合成 composite。
2282
- totalPerUnitDiscount = (product.discount_list || []).reduce(function (sum, pd) {
2283
- return sum + (pd.amount || 0);
2284
- }, 0);
2285
- optionSum = sumOptionUnitPrice(product.product_option_item);
2286
- sourcePrice = (_product$metadata$sou = (_product$metadata3 = product.metadata) === null || _product$metadata3 === void 0 ? void 0 : _product$metadata3.source_product_price) !== null && _product$metadata$sou !== void 0 ? _product$metadata$sou : ((_product$metadata4 = product.metadata) === null || _product$metadata4 === void 0 ? void 0 : _product$metadata4.main_product_original_price) != null ? new Decimal(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : (_product$original_pri = product.original_price) !== null && _product$original_pri !== void 0 ? _product$original_pri : '0';
2287
- newSourceSellingPrice = new Decimal(Number(sourcePrice) || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
2288
- newMainSellingPrice = new Decimal(Number(newSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
2289
- if (product.metadata) {
2290
- product.metadata.main_product_selling_price = newMainSellingPrice;
2291
- product.metadata.price_schema_version = 2;
2292
- }
2293
- product.selling_price = composeLinePrice({
2294
- mainPrice: newMainSellingPrice,
2295
- bundle: product.product_bundle
2296
- });
2297
- case 33:
2298
- _context21.next = 21;
2299
- break;
2300
- case 35:
2301
- _context21.next = 40;
2302
- break;
2303
- case 37:
2304
- _context21.prev = 37;
2305
- _context21.t0 = _context21["catch"](19);
2306
- _iterator15.e(_context21.t0);
2307
- case 40:
2308
- _context21.prev = 40;
2309
- _iterator15.f();
2310
- return _context21.finish(40);
2311
- case 43:
2288
+ this.normalizeDiscountedOrderPrices(nextDiscountList);
2312
2289
  OrderModule.populateSavedAmounts(tempOrder.products, nextDiscountList);
2313
- _context21.next = 46;
2290
+ _context21.next = 21;
2314
2291
  return discountModule === null || discountModule === void 0 ? void 0 : discountModule.setDiscountList(nextDiscountList);
2315
- case 46:
2292
+ case 21:
2316
2293
  tempOrder.discount_list = (nextDiscountList || []).filter(function (d) {
2317
2294
  return d.isSelected;
2318
2295
  });
2319
2296
  afterApplyTarget = this.store.order.getDiscountList().find(function (d) {
2320
2297
  return d.id === params.discountId;
2321
2298
  }) || null;
2322
- _context21.next = 50;
2299
+ _context21.next = 25;
2323
2300
  return this.store.order.recalculateSummary({
2324
2301
  createIfMissing: true
2325
2302
  });
2326
- case 50:
2303
+ case 25:
2327
2304
  this.store.order.persistTempOrder();
2328
2305
  finalSummary = ((_this$store$order$get = this.store.order.getTempOrder()) === null || _this$store$order$get === void 0 ? void 0 : _this$store$order$get.summary) || null;
2329
2306
  finalProduct = ((_this$store$order$get2 = this.store.order.getTempOrder()) === null || _this$store$order$get2 === void 0 || (_this$store$order$get2 = _this$store$order$get2.products) === null || _this$store$order$get2 === void 0 ? void 0 : _this$store$order$get2[0]) || null;
@@ -2332,22 +2309,78 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2332
2309
  return d.id === params.discountId;
2333
2310
  }) || null;
2334
2311
  return _context21.abrupt("return", this.store.order.getDiscountList());
2335
- case 58:
2336
- _context21.prev = 58;
2337
- _context21.t1 = _context21["catch"](1);
2338
- this.logMethodError('setDiscountSelected', _context21.t1);
2339
- throw _context21.t1;
2340
- case 62:
2312
+ case 33:
2313
+ _context21.prev = 33;
2314
+ _context21.t0 = _context21["catch"](1);
2315
+ this.logMethodError('setDiscountSelected', _context21.t0);
2316
+ throw _context21.t0;
2317
+ case 37:
2341
2318
  case "end":
2342
2319
  return _context21.stop();
2343
2320
  }
2344
- }, _callee21, this, [[1, 58], [19, 37, 40, 43]]);
2321
+ }, _callee21, this, [[1, 33]]);
2345
2322
  }));
2346
2323
  function setDiscountSelected(_x15) {
2347
2324
  return _setDiscountSelected.apply(this, arguments);
2348
2325
  }
2349
2326
  return setDiscountSelected;
2350
- }())
2327
+ }()
2328
+ /**
2329
+ * 统一 VenueBooking 折扣后的订单行价。
2330
+ *
2331
+ * Rules 的 `discount_list.amount` 是已经按适用规则计算出的每件优惠额;它是这里唯一
2332
+ * 的折扣金额来源。使用智能定价写入的 source_product_price 减去该金额,再同步
2333
+ * selling_price 与 Summary 使用的 main_product_selling_price,避免 UI 的购物车行价、
2334
+ * 小计和提交订单各自读取到不同的价格字段。
2335
+ */
2336
+ )
2337
+ }, {
2338
+ key: "normalizeDiscountedOrderPrices",
2339
+ value: function normalizeDiscountedOrderPrices(discountList) {
2340
+ var order = this.store.order;
2341
+ if (!order) return;
2342
+ var tempOrder = order.ensureTempOrder();
2343
+ var selectedResourceIds = new Set((discountList || []).filter(function (discount) {
2344
+ return discount.isSelected;
2345
+ }).map(function (discount) {
2346
+ return discount.id;
2347
+ }));
2348
+ var _iterator15 = _createForOfIteratorHelper(tempOrder.products),
2349
+ _step15;
2350
+ try {
2351
+ for (_iterator15.s(); !(_step15 = _iterator15.n()).done;) {
2352
+ var _product$_origin, _metadata$source_prod, _product$original_pri;
2353
+ var product = _step15.value;
2354
+ // 手动改价商品不参与券流程归一化,保留手工价格。
2355
+ if ((_product$_origin = product._origin) !== null && _product$_origin !== void 0 && _product$_origin.isManualDiscount) continue;
2356
+
2357
+ // Rules 可能保留已取消折扣的明细;先使行级明细和当前选择状态一致。
2358
+ product.discount_list = (product.discount_list || []).filter(function (detail) {
2359
+ var _detail$discount$reso, _detail$discount;
2360
+ var resourceId = (_detail$discount$reso = (_detail$discount = detail.discount) === null || _detail$discount === void 0 ? void 0 : _detail$discount.resource_id) !== null && _detail$discount$reso !== void 0 ? _detail$discount$reso : detail.id;
2361
+ return resourceId != null && selectedResourceIds.has(resourceId);
2362
+ });
2363
+ var totalPerUnitDiscount = (product.discount_list || []).reduce(function (total, detail) {
2364
+ return total.plus(detail.amount || 0);
2365
+ }, new Decimal(0));
2366
+ var metadata = product.metadata || (product.metadata = {});
2367
+ var optionSum = sumOptionUnitPrice(product.product_option_item);
2368
+ var sourcePrice = (_metadata$source_prod = metadata.source_product_price) !== null && _metadata$source_prod !== void 0 ? _metadata$source_prod : metadata.main_product_original_price != null ? new Decimal(Number(metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : (_product$original_pri = product.original_price) !== null && _product$original_pri !== void 0 ? _product$original_pri : '0';
2369
+ var nextSourceSellingPrice = Decimal.max(0, new Decimal(Number(sourcePrice) || 0).minus(totalPerUnitDiscount)).toDecimalPlaces(2).toString();
2370
+ var nextMainSellingPrice = new Decimal(Number(nextSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
2371
+ metadata.main_product_selling_price = nextMainSellingPrice;
2372
+ metadata.price_schema_version = 2;
2373
+ product.selling_price = composeLinePrice({
2374
+ mainPrice: nextMainSellingPrice,
2375
+ bundle: product.product_bundle
2376
+ });
2377
+ }
2378
+ } catch (err) {
2379
+ _iterator15.e(err);
2380
+ } finally {
2381
+ _iterator15.f();
2382
+ }
2383
+ }
2351
2384
  }, {
2352
2385
  key: "addNewOrder",
2353
2386
  value: function () {
@@ -2488,7 +2521,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2488
2521
  key: "addProductToOrder",
2489
2522
  value: function () {
2490
2523
  var _addProductToOrder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee25(product) {
2491
- var _product$metadata5, _product$metadata6, smartPrice, products;
2524
+ var _product$metadata3, _product$metadata4, smartPrice, products;
2492
2525
  return _regeneratorRuntime().wrap(function _callee25$(_context25) {
2493
2526
  while (1) switch (_context25.prev = _context25.next) {
2494
2527
  case 0:
@@ -2503,7 +2536,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2503
2536
  }
2504
2537
  throw new Error('order 模块未初始化');
2505
2538
  case 4:
2506
- if (!((_product$metadata5 = product.metadata) !== null && _product$metadata5 !== void 0 && _product$metadata5.venue_booking) && product.product_id != null) {
2539
+ if (!((_product$metadata3 = product.metadata) !== null && _product$metadata3 !== void 0 && _product$metadata3.venue_booking) && product.product_id != null) {
2507
2540
  smartPrice = getPriceForProductAtDatetime({
2508
2541
  products: this.getAllProductsForSmartPricing(),
2509
2542
  context: this.buildSmartPricingContext(),
@@ -2513,7 +2546,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2513
2546
  });
2514
2547
  product.selling_price = smartPrice;
2515
2548
  product.original_price = smartPrice;
2516
- } else if (product.selling_price != null && !((_product$metadata6 = product.metadata) !== null && _product$metadata6 !== void 0 && _product$metadata6.venue_booking)) {
2549
+ } else if (product.selling_price != null && !((_product$metadata4 = product.metadata) !== null && _product$metadata4 !== void 0 && _product$metadata4.venue_booking)) {
2517
2550
  product.original_price = product.selling_price;
2518
2551
  }
2519
2552
  _context25.next = 7;
@@ -2599,7 +2632,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2599
2632
  key: "removeProductFromOrder",
2600
2633
  value: function () {
2601
2634
  var _removeProductFromOrder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee27(identity) {
2602
- var _this$store$order$get3, _this$store$order7, _this$store$order$ens, _this$store$order8, _tempOrder$bookings, tempOrder, products, _tempOrder$bookings2, _tempOrder$bookings3, venueProductUids, venueBookingUids, _iterator16, _step16, _product$metadata7, _product$metadata8, product, beforeBookingCount, _this$store$order$per, _this$store$order9;
2635
+ var _this$store$order$get3, _this$store$order7, _this$store$order$ens, _this$store$order8, _tempOrder$bookings, tempOrder, products, _tempOrder$bookings2, _tempOrder$bookings3, venueProductUids, venueBookingUids, _iterator16, _step16, _product$metadata5, _product$metadata6, product, beforeBookingCount, _this$store$order$per, _this$store$order9;
2603
2636
  return _regeneratorRuntime().wrap(function _callee27$(_context27) {
2604
2637
  while (1) switch (_context27.prev = _context27.next) {
2605
2638
  case 0:
@@ -2634,14 +2667,14 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2634
2667
  break;
2635
2668
  }
2636
2669
  product = _step16.value;
2637
- if (product !== null && product !== void 0 && (_product$metadata7 = product.metadata) !== null && _product$metadata7 !== void 0 && _product$metadata7.venue_booking) {
2670
+ if (product !== null && product !== void 0 && (_product$metadata5 = product.metadata) !== null && _product$metadata5 !== void 0 && _product$metadata5.venue_booking) {
2638
2671
  _context27.next = 18;
2639
2672
  break;
2640
2673
  }
2641
2674
  return _context27.abrupt("continue", 20);
2642
2675
  case 18:
2643
2676
  if (product.identity_key) venueProductUids.add(String(product.identity_key));
2644
- if ((_product$metadata8 = product.metadata) !== null && _product$metadata8 !== void 0 && _product$metadata8.booking_uid) {
2677
+ if ((_product$metadata6 = product.metadata) !== null && _product$metadata6 !== void 0 && _product$metadata6.booking_uid) {
2645
2678
  venueBookingUids.add(String(product.metadata.booking_uid));
2646
2679
  }
2647
2680
  case 20:
@@ -3568,4 +3601,5 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
3568
3601
  return VenueBookingImpl;
3569
3602
  }(BaseModule);
3570
3603
  _defineProperty(VenueBookingImpl, "OPEN_DATA_CACHE_TTL", 5 * 60 * 1000);
3604
+ _defineProperty(VenueBookingImpl, "PISELL1_LOGIN_SUCCESS", 'pisell1.login.success');
3571
3605
  _defineProperty(VenueBookingImpl, "UI_STATE_KEY_PREFIX", 'pisell.venueBooking.uiState:');
@@ -6,7 +6,9 @@ export declare enum VenueBookingHooks {
6
6
  onDestroy = "venueBooking:onDestroy",
7
7
  onRetryInit = "venueBooking:onRetryInit",
8
8
  onRefresh = "venueBooking:onRefresh",
9
- onCartValidationChanged = "venueBooking:onCartValidationChanged"
9
+ onCartValidationChanged = "venueBooking:onCartValidationChanged",
10
+ /** 登录客户的智能定价、营销配置与订单汇总已完成刷新 */
11
+ onSmartPricingUpdated = "venueBooking:onSmartPricingUpdated"
10
12
  }
11
13
  export type VenueBookingStatus = 'idle' | 'initializing' | 'ready' | 'error';
12
14
  export interface VenueBookingEntryContext {
@@ -4,6 +4,7 @@ export var VenueBookingHooks = /*#__PURE__*/function (VenueBookingHooks) {
4
4
  VenueBookingHooks["onRetryInit"] = "venueBooking:onRetryInit";
5
5
  VenueBookingHooks["onRefresh"] = "venueBooking:onRefresh";
6
6
  VenueBookingHooks["onCartValidationChanged"] = "venueBooking:onCartValidationChanged";
7
+ VenueBookingHooks["onSmartPricingUpdated"] = "venueBooking:onSmartPricingUpdated";
7
8
  return VenueBookingHooks;
8
9
  }({});
9
10
 
@@ -0,0 +1,49 @@
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
+ });
@@ -310,7 +310,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
310
310
  date: string;
311
311
  status: string;
312
312
  week: string;
313
- weekNum: 0 | 1 | 5 | 4 | 2 | 3 | 6;
313
+ weekNum: 0 | 2 | 1 | 5 | 4 | 3 | 6;
314
314
  }[]>;
315
315
  submitTimeSlot(timeSlots: TimeSliceItem): void;
316
316
  private getScheduleDataByIds;
@@ -329,7 +329,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
329
329
  count: number;
330
330
  left: number;
331
331
  summaryCount: number;
332
- status: "sold_out" | "lots_of_space" | "filling_up_fast";
332
+ status: "lots_of_space" | "filling_up_fast" | "sold_out";
333
333
  }[];
334
334
  /**
335
335
  * 找到多个资源的公共可用时间段
@@ -37,6 +37,8 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
37
37
  private loginEffectDisposers;
38
38
  private customerLoginRefreshInFlight;
39
39
  private customerLoginRefreshIdInFlight;
40
+ /** 最近一次确认登录的客户;登录事件与 user 插件更新之间可能存在时序差。 */
41
+ private smartPricingCustomerId;
40
42
  private loadAllProductsInFlight;
41
43
  private productsLoaded;
42
44
  private loadOpenDataConfigInFlight;
@@ -45,6 +47,7 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
45
47
  private slotPriceMapCache;
46
48
  /** loadProducts 后缓存的全量商品(venue + addon),供分段算价复用 */
47
49
  private smartPricingProductCatalog;
50
+ private static readonly PISELL1_LOGIN_SUCCESS;
48
51
  private getLoggerContext;
49
52
  private safeStringify;
50
53
  private pickErrorMessage;
@@ -170,6 +173,11 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
170
173
  customerId: number;
171
174
  }): Promise<void>;
172
175
  private recalculateOrderPricesFromSmartPricing;
176
+ /**
177
+ * DataVariant 重算价格后,同步刷新订单展示、Rules 与 Summary 共用的价格口径。
178
+ * Rules 会在本轮结束后根据当前客户的 discountList 重新写入实际折扣。
179
+ */
180
+ private resetProductPriceForSmartPricing;
173
181
  scanCode(code: string, customerId?: number): Promise<{
174
182
  isAvailable: boolean;
175
183
  discountList: import("../../modules/Discount").Discount[];
@@ -184,6 +192,15 @@ export declare class VenueBookingImpl extends BaseModule implements Module {
184
192
  discountId: number;
185
193
  isSelected: boolean;
186
194
  }): Promise<import("../../modules/Discount").Discount[]>;
195
+ /**
196
+ * 统一 VenueBooking 折扣后的订单行价。
197
+ *
198
+ * Rules 的 `discount_list.amount` 是已经按适用规则计算出的每件优惠额;它是这里唯一
199
+ * 的折扣金额来源。使用智能定价写入的 source_product_price 减去该金额,再同步
200
+ * selling_price 与 Summary 使用的 main_product_selling_price,避免 UI 的购物车行价、
201
+ * 小计和提交订单各自读取到不同的价格字段。
202
+ */
203
+ private normalizeDiscountedOrderPrices;
187
204
  addNewOrder(): Promise<import("./types").ScanOrderTempOrder>;
188
205
  getOrderProducts(): ScanOrderOrderProduct[];
189
206
  getSummary(): Promise<import("./types").ScanOrderSummary>;
@@ -277,19 +277,16 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
277
277
  });
278
278
  }
279
279
  registerCustomerLoginListeners() {
280
- var _a, _b, _c, _d;
281
280
  this.clearLoginEffectListeners();
282
- const accountModule = (_a = this.core) == null ? void 0 : _a.getModule("account");
283
- const registerAndLoginModule = (_b = this.core) == null ? void 0 : _b.getModule("registerAndLogin");
284
- const currentAccount = ((_c = accountModule == null ? void 0 : accountModule.getCurrentAccount) == null ? void 0 : _c.call(accountModule)) || ((_d = accountModule == null ? void 0 : accountModule.getAccount) == null ? void 0 : _d.call(accountModule)) || null;
285
- const createHandleLogin = (eventName) => async (payload) => {
281
+ const createHandleLogin = () => async (payload) => {
286
282
  const customerId = this.resolveCustomerIdFromLoginPayload(payload);
287
283
  if (!customerId)
288
284
  return;
289
285
  await this.refreshOrderMarketingAfterLogin({ customerId });
290
286
  };
291
- this.registerLoginEffect(import_types3.AccountHooks.OnLogin, createHandleLogin(import_types3.AccountHooks.OnLogin));
292
- this.registerLoginEffect(import_types4.RegisterAndLoginHooks.onLoginSuccess, createHandleLogin(import_types4.RegisterAndLoginHooks.onLoginSuccess));
287
+ this.registerLoginEffect(_VenueBookingImpl.PISELL1_LOGIN_SUCCESS, createHandleLogin());
288
+ this.registerLoginEffect(import_types3.AccountHooks.OnLogin, createHandleLogin());
289
+ this.registerLoginEffect(import_types4.RegisterAndLoginHooks.onLoginSuccess, createHandleLogin());
293
290
  }
294
291
  async refreshOrderMarketingAfterLogin(params) {
295
292
  if (!this.store.order)
@@ -303,15 +300,24 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
303
300
  }
304
301
  this.customerLoginRefreshIdInFlight = params.customerId;
305
302
  const refreshTask = (async () => {
303
+ var _a, _b, _c;
304
+ this.smartPricingCustomerId = params.customerId;
306
305
  await this.store.order.loadDiscountConfig({
307
306
  customerId: params.customerId
308
307
  });
309
308
  this.clearSlotPriceMapCache();
310
309
  this.recalculateOrderPricesFromSmartPricing();
310
+ this.store.order.applyDiscount();
311
+ this.normalizeDiscountedOrderPrices(
312
+ this.store.order.getDiscountList()
313
+ );
311
314
  await this.store.order.recalculateSummary({ createIfMissing: true });
312
315
  this.store.order.persistTempOrder();
313
316
  await this.refreshItemRuleQuantityLimits();
314
317
  await this.refreshCartValidationPassed();
318
+ await ((_c = (_b = (_a = this.core) == null ? void 0 : _a.effects) == null ? void 0 : _b.emit) == null ? void 0 : _c.call(_b, import_types.VenueBookingHooks.onSmartPricingUpdated, {
319
+ customerId: params.customerId
320
+ }));
315
321
  })();
316
322
  this.customerLoginRefreshInFlight = refreshTask;
317
323
  try {
@@ -331,6 +337,7 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
331
337
  this.core = core;
332
338
  this.initializeOptions = options || {};
333
339
  this.store = { ...this.store, ...options.store };
340
+ this.smartPricingCustomerId = void 0;
334
341
  this.store.entryContext = ((_a = options.otherParams) == null ? void 0 : _a.entryContext) || this.store.entryContext;
335
342
  this.store.status = "initializing";
336
343
  this.store.error = null;
@@ -544,6 +551,8 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
544
551
  /** 读取当前登录 customerId */
545
552
  resolveCustomerIdForSmartPricing() {
546
553
  var _a, _b, _c;
554
+ if (this.smartPricingCustomerId)
555
+ return this.smartPricingCustomerId;
547
556
  try {
548
557
  const userPlugin = (_a = this.core) == null ? void 0 : _a.getPlugin("user");
549
558
  const customerId = Number((_c = (_b = userPlugin == null ? void 0 : userPlugin.get) == null ? void 0 : _b.call(userPlugin)) == null ? void 0 : _c.id);
@@ -1331,11 +1340,13 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1331
1340
  });
1332
1341
  const merged = (0, import_slotMerge.mergeConsecutiveSlots)(updatedSlots);
1333
1342
  if (merged.length === 1) {
1334
- product.selling_price = merged[0].totalPrice;
1335
- product.original_price = merged[0].totalPrice;
1336
- product.metadata.price_breakdown = (0, import_slotMerge.buildPriceBreakdown)({
1337
- group: merged[0],
1338
- productId: mapping.productId
1343
+ this.resetProductPriceForSmartPricing({
1344
+ product,
1345
+ price: merged[0].totalPrice,
1346
+ priceBreakdown: (0, import_slotMerge.buildPriceBreakdown)({
1347
+ group: merged[0],
1348
+ productId: mapping.productId
1349
+ })
1339
1350
  });
1340
1351
  }
1341
1352
  } else if (product.product_id != null) {
@@ -1346,11 +1357,32 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1346
1357
  datetime: now,
1347
1358
  fallbackPrice: product.selling_price
1348
1359
  });
1349
- product.selling_price = smartPrice;
1350
- product.original_price = smartPrice;
1360
+ this.resetProductPriceForSmartPricing({
1361
+ product,
1362
+ price: smartPrice
1363
+ });
1351
1364
  }
1352
1365
  }
1353
1366
  }
1367
+ /**
1368
+ * DataVariant 重算价格后,同步刷新订单展示、Rules 与 Summary 共用的价格口径。
1369
+ * Rules 会在本轮结束后根据当前客户的 discountList 重新写入实际折扣。
1370
+ */
1371
+ resetProductPriceForSmartPricing(params) {
1372
+ const { product, price, priceBreakdown } = params;
1373
+ const metadata = product.metadata || {};
1374
+ product.selling_price = price;
1375
+ product.original_price = price;
1376
+ product.discount_list = [];
1377
+ product.metadata = {
1378
+ ...metadata,
1379
+ ...priceBreakdown ? { price_breakdown: priceBreakdown } : {},
1380
+ source_product_price: price,
1381
+ main_product_original_price: price,
1382
+ main_product_selling_price: price,
1383
+ price_schema_version: 2
1384
+ };
1385
+ }
1354
1386
  async scanCode(code, customerId) {
1355
1387
  this.logMethodStart("scanCode", { code });
1356
1388
  try {
@@ -1376,7 +1408,7 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1376
1408
  }
1377
1409
  /** 勾选/取消勾选某张折扣券,重新计算折扣并持久化 */
1378
1410
  async setDiscountSelected(params) {
1379
- var _a, _b, _c, _d, _e, _f, _g, _h;
1411
+ var _a, _b, _c, _d, _e;
1380
1412
  this.logMethodStart("setDiscountSelected", params);
1381
1413
  try {
1382
1414
  if (!this.store.order)
@@ -1428,42 +1460,15 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1428
1460
  }
1429
1461
  }
1430
1462
  }
1431
- const selectedResourceIds = new Set(
1432
- nextDiscountList.filter((d) => d.isSelected).map((d) => d.id)
1433
- );
1434
- for (const product of tempOrder.products) {
1435
- if ((_c = product._origin) == null ? void 0 : _c.isManualDiscount)
1436
- continue;
1437
- product.discount_list = (product.discount_list || []).filter((pd) => {
1438
- var _a2;
1439
- const rid = ((_a2 = pd.discount) == null ? void 0 : _a2.resource_id) ?? pd.id;
1440
- return rid != null && selectedResourceIds.has(rid);
1441
- });
1442
- const totalPerUnitDiscount = (product.discount_list || []).reduce(
1443
- (sum, pd) => sum + (pd.amount || 0),
1444
- 0
1445
- );
1446
- const optionSum = (0, import_utils3.sumOptionUnitPrice)(product.product_option_item);
1447
- const sourcePrice = ((_d = product.metadata) == null ? void 0 : _d.source_product_price) ?? (((_e = product.metadata) == null ? void 0 : _e.main_product_original_price) != null ? new import_decimal.default(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : product.original_price ?? "0");
1448
- const newSourceSellingPrice = new import_decimal.default(Number(sourcePrice) || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
1449
- const newMainSellingPrice = new import_decimal.default(Number(newSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
1450
- if (product.metadata) {
1451
- product.metadata.main_product_selling_price = newMainSellingPrice;
1452
- product.metadata.price_schema_version = 2;
1453
- }
1454
- product.selling_price = (0, import_utils3.composeLinePrice)({
1455
- mainPrice: newMainSellingPrice,
1456
- bundle: product.product_bundle
1457
- });
1458
- }
1463
+ this.normalizeDiscountedOrderPrices(nextDiscountList);
1459
1464
  import_Order.OrderModule.populateSavedAmounts(tempOrder.products, nextDiscountList);
1460
1465
  await (discountModule == null ? void 0 : discountModule.setDiscountList(nextDiscountList));
1461
1466
  tempOrder.discount_list = (nextDiscountList || []).filter((d) => d.isSelected);
1462
1467
  const afterApplyTarget = this.store.order.getDiscountList().find((d) => d.id === params.discountId) || null;
1463
1468
  await this.store.order.recalculateSummary({ createIfMissing: true });
1464
1469
  this.store.order.persistTempOrder();
1465
- const finalSummary = ((_f = this.store.order.getTempOrder()) == null ? void 0 : _f.summary) || null;
1466
- const finalProduct = ((_h = (_g = this.store.order.getTempOrder()) == null ? void 0 : _g.products) == null ? void 0 : _h[0]) || null;
1470
+ const finalSummary = ((_c = this.store.order.getTempOrder()) == null ? void 0 : _c.summary) || null;
1471
+ const finalProduct = ((_e = (_d = this.store.order.getTempOrder()) == null ? void 0 : _d.products) == null ? void 0 : _e[0]) || null;
1467
1472
  this.logMethodSuccess("setDiscountSelected", params);
1468
1473
  const finalTarget = this.store.order.getDiscountList().find((d) => d.id === params.discountId) || null;
1469
1474
  return this.store.order.getDiscountList();
@@ -1472,6 +1477,51 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
1472
1477
  throw error;
1473
1478
  }
1474
1479
  }
1480
+ /**
1481
+ * 统一 VenueBooking 折扣后的订单行价。
1482
+ *
1483
+ * Rules 的 `discount_list.amount` 是已经按适用规则计算出的每件优惠额;它是这里唯一
1484
+ * 的折扣金额来源。使用智能定价写入的 source_product_price 减去该金额,再同步
1485
+ * selling_price 与 Summary 使用的 main_product_selling_price,避免 UI 的购物车行价、
1486
+ * 小计和提交订单各自读取到不同的价格字段。
1487
+ */
1488
+ normalizeDiscountedOrderPrices(discountList) {
1489
+ var _a;
1490
+ const order = this.store.order;
1491
+ if (!order)
1492
+ return;
1493
+ const tempOrder = order.ensureTempOrder();
1494
+ const selectedResourceIds = new Set(
1495
+ (discountList || []).filter((discount) => discount.isSelected).map((discount) => discount.id)
1496
+ );
1497
+ for (const product of tempOrder.products) {
1498
+ if ((_a = product._origin) == null ? void 0 : _a.isManualDiscount)
1499
+ continue;
1500
+ product.discount_list = (product.discount_list || []).filter((detail) => {
1501
+ var _a2;
1502
+ const resourceId = ((_a2 = detail.discount) == null ? void 0 : _a2.resource_id) ?? detail.id;
1503
+ return resourceId != null && selectedResourceIds.has(resourceId);
1504
+ });
1505
+ const totalPerUnitDiscount = (product.discount_list || []).reduce(
1506
+ (total, detail) => total.plus(detail.amount || 0),
1507
+ new import_decimal.default(0)
1508
+ );
1509
+ const metadata = product.metadata || (product.metadata = {});
1510
+ const optionSum = (0, import_utils3.sumOptionUnitPrice)(product.product_option_item);
1511
+ const sourcePrice = metadata.source_product_price ?? (metadata.main_product_original_price != null ? new import_decimal.default(Number(metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : product.original_price ?? "0");
1512
+ const nextSourceSellingPrice = import_decimal.default.max(
1513
+ 0,
1514
+ new import_decimal.default(Number(sourcePrice) || 0).minus(totalPerUnitDiscount)
1515
+ ).toDecimalPlaces(2).toString();
1516
+ const nextMainSellingPrice = new import_decimal.default(Number(nextSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
1517
+ metadata.main_product_selling_price = nextMainSellingPrice;
1518
+ metadata.price_schema_version = 2;
1519
+ product.selling_price = (0, import_utils3.composeLinePrice)({
1520
+ mainPrice: nextMainSellingPrice,
1521
+ bundle: product.product_bundle
1522
+ });
1523
+ }
1524
+ }
1475
1525
  async addNewOrder() {
1476
1526
  this.logMethodStart("addNewOrder");
1477
1527
  try {
@@ -2019,6 +2069,7 @@ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
2019
2069
  };
2020
2070
  var VenueBookingImpl = _VenueBookingImpl;
2021
2071
  VenueBookingImpl.OPEN_DATA_CACHE_TTL = 5 * 60 * 1e3;
2072
+ VenueBookingImpl.PISELL1_LOGIN_SUCCESS = "pisell1.login.success";
2022
2073
  // ─── UI 状态缓存(按 cacheId 分桶,sessionStorage) ───
2023
2074
  //
2024
2075
  // 用于物料层持久化 UI 层面的轻量状态(如当前步骤、登录回跳意图等)。
@@ -6,7 +6,9 @@ export declare enum VenueBookingHooks {
6
6
  onDestroy = "venueBooking:onDestroy",
7
7
  onRetryInit = "venueBooking:onRetryInit",
8
8
  onRefresh = "venueBooking:onRefresh",
9
- onCartValidationChanged = "venueBooking:onCartValidationChanged"
9
+ onCartValidationChanged = "venueBooking:onCartValidationChanged",
10
+ /** 登录客户的智能定价、营销配置与订单汇总已完成刷新 */
11
+ onSmartPricingUpdated = "venueBooking:onSmartPricingUpdated"
10
12
  }
11
13
  export type VenueBookingStatus = 'idle' | 'initializing' | 'ready' | 'error';
12
14
  export interface VenueBookingEntryContext {
@@ -29,6 +29,7 @@ var VenueBookingHooks = /* @__PURE__ */ ((VenueBookingHooks2) => {
29
29
  VenueBookingHooks2["onRetryInit"] = "venueBooking:onRetryInit";
30
30
  VenueBookingHooks2["onRefresh"] = "venueBooking:onRefresh";
31
31
  VenueBookingHooks2["onCartValidationChanged"] = "venueBooking:onCartValidationChanged";
32
+ VenueBookingHooks2["onSmartPricingUpdated"] = "venueBooking:onSmartPricingUpdated";
32
33
  return VenueBookingHooks2;
33
34
  })(VenueBookingHooks || {});
34
35
  var DEFAULT_SLOT_CONFIG = {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "2.1.163",
4
+ "version": "2.1.164",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",