@pisell/pisellos 0.0.508 → 0.0.510

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
- function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
- function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
3
1
  function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
4
2
  function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
5
- function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
6
3
  function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
7
4
  function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
5
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
6
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
7
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
8
8
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
9
9
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
10
10
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
@@ -25,7 +25,7 @@ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key i
25
25
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
26
26
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
27
27
  import { BaseModule } from "../BaseModule";
28
- import { generateDuration, getAllDiscountList, mergeRelationForms, buildSubmitPayload, createDefaultTempOrder, createDefaultOrderRulesHooks, createEmptySummary, formatDateTime, formatV1Product, isTempOrder } from "./utils";
28
+ import { generateDuration, getAllDiscountList, mergeRelationForms, buildSubmitPayload, createDefaultTempOrder, createDefaultOrderRulesHooks, createEmptySummary, formatDateTime, filterProductsForScanOrderMore, formatV1Product, isTempOrder } from "./utils";
29
29
  import { isNormalProduct } from "../Product/utils";
30
30
  import dayjs from 'dayjs';
31
31
  import { getProductIdentityIndex, getSafeProductNum, isIdentityMatch, normalizeOrderProduct } from "../../solution/ScanOrder/utils";
@@ -387,6 +387,26 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
387
387
  this.window.localStorage.removeItem(key);
388
388
  return;
389
389
  }
390
+ if (Array.isArray(parsedData.products)) {
391
+ var _iterator = _createForOfIteratorHelper(parsedData.products),
392
+ _step;
393
+ try {
394
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
395
+ var p = _step.value;
396
+ if (!p || _typeof(p) !== 'object') continue;
397
+ if (!Array.isArray(p.product_option_item)) {
398
+ p.product_option_item = [];
399
+ }
400
+ if (!Array.isArray(p.product_bundle)) {
401
+ p.product_bundle = [];
402
+ }
403
+ }
404
+ } catch (err) {
405
+ _iterator.e(err);
406
+ } finally {
407
+ _iterator.f();
408
+ }
409
+ }
390
410
  this.store.tempOrder = parsedData;
391
411
  } catch (_unused2) {
392
412
  var _this$window;
@@ -676,32 +696,23 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
676
696
  key: "removeProductFromOrder",
677
697
  value: function () {
678
698
  var _removeProductFromOrder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee9(identity) {
679
- var tempOrder, beforeProducts, removedByStrictIdentity;
699
+ var tempOrder;
680
700
  return _regeneratorRuntime().wrap(function _callee9$(_context9) {
681
701
  while (1) switch (_context9.prev = _context9.next) {
682
702
  case 0:
683
703
  tempOrder = this.ensureTempOrder();
684
- beforeProducts = tempOrder.products;
685
704
  tempOrder.products = tempOrder.products.filter(function (item) {
686
705
  return !isIdentityMatch(item, identity);
687
706
  });
688
- removedByStrictIdentity = beforeProducts.length - tempOrder.products.length;
689
- if (removedByStrictIdentity === 0 && identity.identity_key) {
690
- tempOrder.products = tempOrder.products.filter(function (item) {
691
- var isSameProduct = String(item.product_id) === String(identity.product_id) && String(item.product_variant_id) === String(identity.product_variant_id);
692
- var hasNoIdentityKey = !item.identity_key;
693
- return !(isSameProduct && hasNoIdentityKey);
694
- });
695
- }
696
707
  this.applyDiscount();
697
- _context9.next = 8;
708
+ _context9.next = 5;
698
709
  return this.recalculateSummary({
699
710
  createIfMissing: true
700
711
  });
701
- case 8:
712
+ case 5:
702
713
  this.persistTempOrder();
703
714
  return _context9.abrupt("return", tempOrder.products);
704
- case 10:
715
+ case 7:
705
716
  case "end":
706
717
  return _context9.stop();
707
718
  }
@@ -737,7 +748,7 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
737
748
  _context10.next = 12;
738
749
  break;
739
750
  }
740
- products = formatV1Product(payload.products);
751
+ products = formatV1Product(filterProductsForScanOrderMore(payload.products));
741
752
  _context10.next = 8;
742
753
  return this.scanOrderMore({
743
754
  query: {
@@ -1135,46 +1146,46 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
1135
1146
  */
1136
1147
  function populateSavedAmounts(productList, discountList) {
1137
1148
  var savedMap = new Map();
1138
- var _iterator = _createForOfIteratorHelper(productList),
1139
- _step;
1149
+ var _iterator2 = _createForOfIteratorHelper(productList),
1150
+ _step2;
1140
1151
  try {
1141
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
1142
- var product = _step.value;
1152
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1153
+ var product = _step2.value;
1143
1154
  var qty = product.num || 1;
1144
- var _iterator3 = _createForOfIteratorHelper(product.discount_list || []),
1145
- _step3;
1155
+ var _iterator4 = _createForOfIteratorHelper(product.discount_list || []),
1156
+ _step4;
1146
1157
  try {
1147
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
1158
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
1148
1159
  var _pd$discount, _pd$metadata;
1149
- var pd = _step3.value;
1160
+ var pd = _step4.value;
1150
1161
  var discountKey = ((_pd$discount = pd.discount) === null || _pd$discount === void 0 ? void 0 : _pd$discount.resource_id) || pd.id;
1151
1162
  if (discountKey == null) continue;
1152
1163
  var amount = new Decimal(pd.amount || 0).times(qty).plus(((_pd$metadata = pd.metadata) === null || _pd$metadata === void 0 ? void 0 : _pd$metadata.product_discount_difference) || 0);
1153
1164
  savedMap.set(discountKey, (savedMap.get(discountKey) || new Decimal(0)).plus(amount));
1154
1165
  }
1155
1166
  } catch (err) {
1156
- _iterator3.e(err);
1167
+ _iterator4.e(err);
1157
1168
  } finally {
1158
- _iterator3.f();
1169
+ _iterator4.f();
1159
1170
  }
1160
1171
  }
1161
1172
  } catch (err) {
1162
- _iterator.e(err);
1173
+ _iterator2.e(err);
1163
1174
  } finally {
1164
- _iterator.f();
1175
+ _iterator2.f();
1165
1176
  }
1166
- var _iterator2 = _createForOfIteratorHelper(discountList),
1167
- _step2;
1177
+ var _iterator3 = _createForOfIteratorHelper(discountList),
1178
+ _step3;
1168
1179
  try {
1169
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
1170
- var d = _step2.value;
1180
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
1181
+ var d = _step3.value;
1171
1182
  var key = d.id;
1172
1183
  d.savedAmount = d.isSelected && key != null && savedMap.has(key) ? savedMap.get(key).toNumber() : 0;
1173
1184
  }
1174
1185
  } catch (err) {
1175
- _iterator2.e(err);
1186
+ _iterator3.e(err);
1176
1187
  } finally {
1177
- _iterator2.f();
1188
+ _iterator3.f();
1178
1189
  }
1179
1190
  }
1180
1191
  }]);
@@ -72,6 +72,8 @@ export declare function buildSubmitPayload(params: {
72
72
  type?: string;
73
73
  enhance?: SubmitPayloadEnhancer;
74
74
  }): ScanOrderSubmitPayload;
75
+ /** 加单(scanOrderMore)不应提交 booking 关联的虚拟规则商品行 */
76
+ export declare function filterProductsForScanOrderMore(products: ScanOrderSubmitProduct[]): ScanOrderSubmitProduct[];
75
77
  export declare function formatV1Product(products: ScanOrderSubmitProduct[]): {
76
78
  bundle: any[];
77
79
  key: number | null;
@@ -18,7 +18,7 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
18
18
  function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
19
19
  import dayjs from "dayjs";
20
20
  import Decimal from 'decimal.js';
21
- import { createEmptySummary } from "../../solution/ScanOrder/utils";
21
+ import { buildProductLineFingerprint, createEmptySummary } from "../../solution/ScanOrder/utils";
22
22
  /**
23
23
  * OrderModule 默认 Rules 钩子工厂。
24
24
  *
@@ -47,7 +47,9 @@ export function createDefaultOrderRulesHooks() {
47
47
  var _product$_origin, _product$_origin2, _product$_origin3, _product$_origin4;
48
48
  return {
49
49
  id: product.product_id,
50
- _id: product.identity_key ? "".concat(product.product_id, "_").concat(product.product_variant_id, "_").concat(product.identity_key) : "".concat(product.product_id, "_").concat(product.product_variant_id),
50
+ // Rules 引擎用 _id 作为 processedProductsMap 键;必须与购物车行级 identity 一致,
51
+ // 否则同 SKU 不同小料会在 calcDiscount 重组时互相覆盖。
52
+ _id: product.identity_key ? "".concat(product.product_id, "_").concat(product.product_variant_id, "_").concat(product.identity_key) : "".concat(product.product_id, "_").concat(product.product_variant_id, "_").concat(buildProductLineFingerprint(product.product_option_item, product.product_bundle)),
51
53
  price: product.selling_price,
52
54
  total: new Decimal(product.selling_price || 0).times(product.num || 1).toNumber(),
53
55
  origin_total: new Decimal(product.original_price || product.selling_price || 0).times(product.num || 1).toNumber(),
@@ -390,6 +392,14 @@ export function buildSubmitPayload(params) {
390
392
  now: now
391
393
  }) : payload;
392
394
  }
395
+
396
+ /** 加单(scanOrderMore)不应提交 booking 关联的虚拟规则商品行 */
397
+ export function filterProductsForScanOrderMore(products) {
398
+ return (products || []).filter(function (p) {
399
+ var _p$metadata;
400
+ return ((_p$metadata = p.metadata) === null || _p$metadata === void 0 ? void 0 : _p$metadata.is_rule) !== true;
401
+ });
402
+ }
393
403
  export function formatV1Product(products) {
394
404
  return products.map(function (product) {
395
405
  return {
@@ -30,7 +30,7 @@ import { OrderModule } from "../../modules/Order";
30
30
  import { AccountHooks } from "../../modules/Account/types";
31
31
  import { RegisterAndLoginHooks } from "../RegisterAndLogin/types";
32
32
  import Decimal from 'decimal.js';
33
- import { attachItemRuleLimitsToTopLevelProducts, buildProductKey, buildItemRuleBusinessData, collectLinkProductIdsFromReservationRules, computeResourceIsFull, createEmptySummary, getProductIdentityIndex, getSafeProductNum, hasCustomCapacityProduct, pickFirstCustomCapacityPaxBounds, normalizeEnabledItemRuleIds, normalizeOrderProduct, normalizeItemRuleStrategies, pickFirstDurationMinutesFromProducts, toNonNegativeInt, toPriceString, toBoolean, toPositiveString } from "./utils";
33
+ import { attachItemRuleLimitsToTopLevelProducts, buildProductKey, buildItemRuleBusinessData, collectLinkProductIdsFromReservationRules, computeResourceIsFull, createEmptySummary, getProductIdentityIndex, getSafeProductNum, hasCustomCapacityProduct, pickFirstCustomCapacityDimensionId, pickFirstCustomCapacityPaxBounds, normalizeEnabledItemRuleIds, normalizeOrderProduct, normalizeItemRuleStrategies, pickFirstDurationMinutesFromProducts, toNonNegativeInt, toPriceString, toBoolean, toPositiveString } from "./utils";
34
34
  import { createModule } from "../BookingByStep/types";
35
35
  import { ProductList } from "../../modules/ProductList";
36
36
  import { ScheduleModule } from "../../modules/Schedule";
@@ -1195,6 +1195,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1195
1195
  }, {
1196
1196
  key: "buildSubmitPayloadEnhancer",
1197
1197
  value: function buildSubmitPayloadEnhancer() {
1198
+ var _this5 = this;
1198
1199
  var ruleProduct = this.enabledReservationRuleProducts[0];
1199
1200
  var resourceState = this.store.resource;
1200
1201
  var resourceSelectType = resourceState === null || resourceState === void 0 ? void 0 : resourceState.resourceSelectType;
@@ -1211,7 +1212,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1211
1212
  return 1;
1212
1213
  };
1213
1214
  return function (payload, _ref3) {
1214
- var _tempOrder$resource_i, _ref4, _pickOriginal, _resourceState$table_2, _resourceState$relati;
1215
+ var _tempOrder$resource_i, _ref4, _pickOriginal, _resourceState$table_2, _resourceState$relati, _tempOrder$metadata, _pickFirstCustomCapac;
1215
1216
  var bookingUuid = _ref3.bookingUuid,
1216
1217
  tempOrder = _ref3.tempOrder;
1217
1218
  var resourceId = (_tempOrder$resource_i = tempOrder.resource_id) !== null && _tempOrder$resource_i !== void 0 ? _tempOrder$resource_i : resourceState === null || resourceState === void 0 ? void 0 : resourceState.relationId;
@@ -1234,7 +1235,11 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1234
1235
  metadata: {}
1235
1236
  } : undefined;
1236
1237
  var ruleProductUid = ruleProduct ? createUuidV4() : undefined;
1237
- var bookingCapacityValue = resolveResourceCapacity();
1238
+ // 默认 resolveResourceCapacity(single 为桌台容量,其余多为 1);有 collect_pax 时 value 优先用人数
1239
+ var rawCollectPax = (_tempOrder$metadata = tempOrder.metadata) === null || _tempOrder$metadata === void 0 ? void 0 : _tempOrder$metadata.collect_pax;
1240
+ var hasCollectPaxForCapacity = rawCollectPax !== null && rawCollectPax !== undefined && rawCollectPax !== '';
1241
+ var bookingCapacityValue = hasCollectPaxForCapacity ? normalizeSubmitCollectPaxValue(rawCollectPax) : resolveResourceCapacity();
1242
+ var bookingCapacityDimensionId = (_pickFirstCustomCapac = pickFirstCustomCapacityDimensionId(_this5.enabledReservationRuleProducts)) !== null && _pickFirstCustomCapac !== void 0 ? _pickFirstCustomCapac : 0;
1238
1243
  var nextBookings = (payload.bookings || []).map(function (booking, idx) {
1239
1244
  return _objectSpread(_objectSpread(_objectSpread({}, booking), {}, {
1240
1245
  appointment_status: 'started',
@@ -1242,7 +1247,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1242
1247
  resource_select_type: resourceSelectType
1243
1248
  } : {}), resourceSelectType ? {
1244
1249
  capacity: [{
1245
- id: 0,
1250
+ id: bookingCapacityDimensionId,
1246
1251
  value: bookingCapacityValue,
1247
1252
  name: ''
1248
1253
  }]
@@ -1254,7 +1259,8 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1254
1259
  } : {});
1255
1260
  });
1256
1261
  var nextProducts = _toConsumableArray(payload.products || []);
1257
- if (ruleProduct && ruleProductUid) {
1262
+ // 加餐(已有 order_id)走 scanOrderMore,原单已含 booking 规则行,勿再追加虚拟规则商品
1263
+ if (ruleProduct && ruleProductUid && !tempOrder.order_id) {
1258
1264
  var _ruleProduct$price, _ref5, _ruleProduct$original, _ruleProduct$is_gst;
1259
1265
  var sellingPrice = String((_ruleProduct$price = ruleProduct.price) !== null && _ruleProduct$price !== void 0 ? _ruleProduct$price : '0.00');
1260
1266
  var originalPrice = String((_ref5 = (_ruleProduct$original = ruleProduct.original_price) !== null && _ruleProduct$original !== void 0 ? _ruleProduct$original : ruleProduct.price) !== null && _ref5 !== void 0 ? _ref5 : '0.00');
@@ -1719,7 +1725,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1719
1725
  key: "ensureItemRuleConfigsLoaded",
1720
1726
  value: function () {
1721
1727
  var _ensureItemRuleConfigsLoaded = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee25() {
1722
- var _this5 = this;
1728
+ var _this6 = this;
1723
1729
  var loadedConfigs;
1724
1730
  return _regeneratorRuntime().wrap(function _callee25$(_context25) {
1725
1731
  while (1) switch (_context25.prev = _context25.next) {
@@ -1741,19 +1747,19 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1741
1747
  return _regeneratorRuntime().wrap(function _callee24$(_context24) {
1742
1748
  while (1) switch (_context24.prev = _context24.next) {
1743
1749
  case 0:
1744
- runtimeConfig = _this5.getItemRuleRuntimeConfig();
1750
+ runtimeConfig = _this6.getItemRuleRuntimeConfig();
1745
1751
  staticConfigs = normalizeItemRuleStrategies(runtimeConfig.strategyConfigs);
1746
1752
  if (!(staticConfigs.length > 0)) {
1747
1753
  _context24.next = 6;
1748
1754
  break;
1749
1755
  }
1750
- _this5.itemRuleConfigs = staticConfigs;
1751
- _this5.itemRuleEvaluator.setStrategyConfigs(staticConfigs);
1752
- return _context24.abrupt("return", _this5.itemRuleConfigs);
1756
+ _this6.itemRuleConfigs = staticConfigs;
1757
+ _this6.itemRuleEvaluator.setStrategyConfigs(staticConfigs);
1758
+ return _context24.abrupt("return", _this6.itemRuleConfigs);
1753
1759
  case 6:
1754
- _this5.itemRuleConfigs = [];
1755
- _this5.itemRuleEvaluator.setStrategyConfigs([]);
1756
- return _context24.abrupt("return", _this5.itemRuleConfigs);
1760
+ _this6.itemRuleConfigs = [];
1761
+ _this6.itemRuleEvaluator.setStrategyConfigs([]);
1762
+ return _context24.abrupt("return", _this6.itemRuleConfigs);
1757
1763
  case 9:
1758
1764
  case "end":
1759
1765
  return _context24.stop();
@@ -2207,7 +2213,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
2207
2213
  var tableFormId = toPositiveString(detail === null || detail === void 0 ? void 0 : detail.form_id);
2208
2214
  var formRecord = (_detail$form_record = detail === null || detail === void 0 ? void 0 : detail.form_record) !== null && _detail$form_record !== void 0 ? _detail$form_record : null;
2209
2215
  // 是否允许加餐
2210
- var allowSnack = ((_this$otherParams8 = this.otherParams) === null || _this$otherParams8 === void 0 || (_this$otherParams8 = _this$otherParams8.dineInConfig) === null || _this$otherParams8 === void 0 ? void 0 : _this$otherParams8['workflow.allow_add_items']) || false;
2216
+ var allowSnack = ((_this$otherParams8 = this.otherParams) === null || _this$otherParams8 === void 0 || (_this$otherParams8 = _this$otherParams8.dineInConfig) === null || _this$otherParams8 === void 0 ? void 0 : _this$otherParams8['sale.allow_add_items']) || false;
2211
2217
  // 开启同桌验证 - 本期没有这个配置,默认关掉
2212
2218
  var deskmateValid = false;
2213
2219
  var isExclusive = resourceSelectType === 'single';
@@ -2723,11 +2729,18 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
2723
2729
  return _setOtherParams.apply(this, arguments);
2724
2730
  }
2725
2731
  return setOtherParams;
2726
- }() // ─── UI 状态缓存(按 cacheId 分桶,sessionStorage) ───
2732
+ }() // ─── UI 状态缓存(按 cacheId 分桶,localStorage) ───
2727
2733
  //
2728
2734
  // 用于物料层持久化 UI 层面的轻量状态(如当前步骤、gate 标记、登录回跳意图等)。
2729
2735
  // 桶键:pisell.scanOrder.uiState:<cacheId>;内部以 JSON object 形式存储多个字段。
2730
2736
  // 无 cacheId 时所有方法自动降级为 no-op,上层不用判空。
2737
+ //
2738
+ // 之所以用 localStorage 而不是 sessionStorage:
2739
+ // 1. 与 Order 模块 openCache 下的 tempOrder 同栈,购物车在 / UIState 在,行为对齐;
2740
+ // 2. pisell1.login 整页 OAuth 跳转在 H5 壳 / iOS Safari 场景下可能丢 sessionStorage,
2741
+ // 导致登录回跳后 gate 标记失效、pax 弹窗重开、落点错误;localStorage 稳定不受影响。
2742
+ // 3. 失效由上层显式控制:提交成功 clearStepCache / entryContext 不一致 clearUIState /
2743
+ // pendingStep 登录回调 deleteUIState,足够约束生命周期。
2731
2744
  }, {
2732
2745
  key: "getUIStateBucketKey",
2733
2746
  value: function getUIStateBucketKey() {
@@ -2739,9 +2752,9 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
2739
2752
  value: function readUIStateBucket() {
2740
2753
  var _this$window;
2741
2754
  var key = this.getUIStateBucketKey();
2742
- if (!key || !((_this$window = this.window) !== null && _this$window !== void 0 && _this$window.sessionStorage)) return {};
2755
+ if (!key || !((_this$window = this.window) !== null && _this$window !== void 0 && _this$window.localStorage)) return {};
2743
2756
  try {
2744
- var raw = this.window.sessionStorage.getItem(key) || '{}';
2757
+ var raw = this.window.localStorage.getItem(key) || '{}';
2745
2758
  var parsed = JSON.parse(raw);
2746
2759
  return parsed && _typeof(parsed) === 'object' ? parsed : {};
2747
2760
  } catch (_unused) {
@@ -2753,9 +2766,9 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
2753
2766
  value: function writeUIStateBucket(bucket) {
2754
2767
  var _this$window2;
2755
2768
  var key = this.getUIStateBucketKey();
2756
- if (!key || !((_this$window2 = this.window) !== null && _this$window2 !== void 0 && _this$window2.sessionStorage)) return;
2769
+ if (!key || !((_this$window2 = this.window) !== null && _this$window2 !== void 0 && _this$window2.localStorage)) return;
2757
2770
  try {
2758
- this.window.sessionStorage.setItem(key, JSON.stringify(bucket));
2771
+ this.window.localStorage.setItem(key, JSON.stringify(bucket));
2759
2772
  } catch (error) {
2760
2773
  console.warn('[ScanOrder] writeUIStateBucket failed', error);
2761
2774
  }
@@ -2792,9 +2805,9 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
2792
2805
  value: function clearUIState() {
2793
2806
  var _this$window3;
2794
2807
  var key = this.getUIStateBucketKey();
2795
- if (!key || !((_this$window3 = this.window) !== null && _this$window3 !== void 0 && _this$window3.sessionStorage)) return;
2808
+ if (!key || !((_this$window3 = this.window) !== null && _this$window3 !== void 0 && _this$window3.localStorage)) return;
2796
2809
  try {
2797
- this.window.sessionStorage.removeItem(key);
2810
+ this.window.localStorage.removeItem(key);
2798
2811
  } catch (error) {
2799
2812
  console.warn('[ScanOrder] clearUIState failed', error);
2800
2813
  }
@@ -31,6 +31,9 @@ export interface ScanOrderOrderProductIdentity {
31
31
  product_id: number | null;
32
32
  product_variant_id: number;
33
33
  identity_key?: string;
34
+ /** 参与合并/匹配;与 remove 通配语义见 isSkuOnlyDeleteIdentity */
35
+ product_option_item?: any[];
36
+ product_bundle?: any[];
34
37
  }
35
38
  export interface ScanOrderOrderProduct extends ScanOrderOrderProductIdentity {
36
39
  order_detail_id: number | null;
@@ -81,10 +81,27 @@ export declare function buildItemRuleBusinessData(params: {
81
81
  itemRuleConfigs: StrategyConfig[];
82
82
  }): ItemRuleBusinessData;
83
83
  export declare function attachItemRuleLimitsToTopLevelProducts<T>(productList: T, limits: QuantityLimitResult[]): T;
84
+ /**
85
+ * 将选项行 / 套餐行归一成稳定 JSON,用于「同 SKU 是否合并」判断。
86
+ * 数组元素先按主键排序再序列化,避免顺序差异导致误判为不同行。
87
+ */
88
+ export declare function buildProductLineFingerprint(productOptionItem?: unknown, productBundle?: unknown): string;
89
+ /**
90
+ * removeProductFromOrder 仅传 SKU 时的通配 identity(对象上未声明选项键)。
91
+ * 与显式 `product_option_item: []` 区分:后者只匹配「无选项」行。
92
+ */
93
+ export declare function isSkuOnlyDeleteIdentity(x: ScanOrderOrderProductIdentity): boolean;
94
+ /**
95
+ * 与常见 UI 约定一致:仅当存在**一条** `product_option_item` 时,
96
+ * `${product_id}_${option_group_id}_${product_option_item_id}_${num}` 可作为删除用 `identity_key`。
97
+ * 多小料行请使用加购时的 `identity_key` / `metadata.unique_identification_number` 或按 `product_option_item` 指纹删除。
98
+ */
99
+ export declare function buildSyntheticSingleOptionIdentityKey(productId: number | null, productOptionItem: unknown): string | undefined;
84
100
  /**
85
101
  * 判断两个商品 identity 是否匹配。
86
- * 当双方都没有 identity_key 时回退到 product_id + product_variant_id 比较(向后兼容);
87
- * 一旦有一方携带 identity_key,则必须严格相等。
102
+ * - 任一方带 `identity_key`:两侧都有则比字符串相等;仅一侧有则比「另一侧有效 key 集合」是否含该 key(见 collectLineIdentityKeyCandidates)。
103
+ * - 否则若任一方为「仅 SKU」删除通配(未声明 product_option_item / product_bundle 键),只比 SKU。
104
+ * - 否则比较选项 + 套餐指纹(同 SKU 且指纹相同才合并数量)。
88
105
  */
89
106
  export declare function isIdentityMatch(a: ScanOrderOrderProductIdentity, b: ScanOrderOrderProductIdentity): boolean;
90
107
  /**
@@ -129,3 +146,8 @@ export declare function pickFirstCustomCapacityPaxBounds(products: ProductData[]
129
146
  min?: number;
130
147
  max?: number;
131
148
  } | undefined;
149
+ /**
150
+ * 第一个 `capacity.type === 'custom'` 的商品,取其 `custom[0].id`(提交 booking metadata.capacity 维度 id)。
151
+ * 无匹配时返回 `undefined`,调用方应回退为 `0`。
152
+ */
153
+ export declare function pickFirstCustomCapacityDimensionId(products: ProductData[]): string | number | undefined;
@@ -366,15 +366,116 @@ export function attachItemRuleLimitsToTopLevelProducts(productList, limits) {
366
366
  return productList;
367
367
  }
368
368
 
369
+ /**
370
+ * 将选项行 / 套餐行归一成稳定 JSON,用于「同 SKU 是否合并」判断。
371
+ * 数组元素先按主键排序再序列化,避免顺序差异导致误判为不同行。
372
+ */
373
+ export function buildProductLineFingerprint(productOptionItem, productBundle) {
374
+ var optArr = Array.isArray(productOptionItem) ? productOptionItem : [];
375
+ var normalizedOpts = optArr.map(function (item) {
376
+ var _item$price;
377
+ return {
378
+ product_option_item_id: Number(item === null || item === void 0 ? void 0 : item.product_option_item_id) || 0,
379
+ option_group_id: Number(item === null || item === void 0 ? void 0 : item.option_group_id) || 0,
380
+ num: typeof (item === null || item === void 0 ? void 0 : item.num) === 'number' && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1,
381
+ price: String((_item$price = item === null || item === void 0 ? void 0 : item.price) !== null && _item$price !== void 0 ? _item$price : '')
382
+ };
383
+ }).sort(function (p, q) {
384
+ if (p.product_option_item_id !== q.product_option_item_id) {
385
+ return p.product_option_item_id - q.product_option_item_id;
386
+ }
387
+ if (p.option_group_id !== q.option_group_id) return p.option_group_id - q.option_group_id;
388
+ if (p.num !== q.num) return p.num - q.num;
389
+ return p.price.localeCompare(q.price);
390
+ });
391
+ var bundleArr = Array.isArray(productBundle) ? productBundle : [];
392
+ var normalizedBundles = bundleArr.map(function (item) {
393
+ var _ref, _item$bundle_id;
394
+ return {
395
+ bundle_id: Number((_ref = (_item$bundle_id = item === null || item === void 0 ? void 0 : item.bundle_id) !== null && _item$bundle_id !== void 0 ? _item$bundle_id : item === null || item === void 0 ? void 0 : item.id) !== null && _ref !== void 0 ? _ref : 0) || 0,
396
+ product_id: Number(item === null || item === void 0 ? void 0 : item.product_id) || 0,
397
+ num: typeof (item === null || item === void 0 ? void 0 : item.num) === 'number' && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1
398
+ };
399
+ }).sort(function (p, q) {
400
+ if (p.bundle_id !== q.bundle_id) return p.bundle_id - q.bundle_id;
401
+ if (p.product_id !== q.product_id) return p.product_id - q.product_id;
402
+ return p.num - q.num;
403
+ });
404
+ return JSON.stringify([normalizedOpts, normalizedBundles]);
405
+ }
406
+
407
+ /**
408
+ * removeProductFromOrder 仅传 SKU 时的通配 identity(对象上未声明选项键)。
409
+ * 与显式 `product_option_item: []` 区分:后者只匹配「无选项」行。
410
+ */
411
+ export function isSkuOnlyDeleteIdentity(x) {
412
+ if (x.identity_key) return false;
413
+ return !('product_option_item' in x) && !('product_bundle' in x);
414
+ }
415
+
416
+ /**
417
+ * 与常见 UI 约定一致:仅当存在**一条** `product_option_item` 时,
418
+ * `${product_id}_${option_group_id}_${product_option_item_id}_${num}` 可作为删除用 `identity_key`。
419
+ * 多小料行请使用加购时的 `identity_key` / `metadata.unique_identification_number` 或按 `product_option_item` 指纹删除。
420
+ */
421
+ export function buildSyntheticSingleOptionIdentityKey(productId, productOptionItem) {
422
+ if (productId == null || !Number.isFinite(Number(productId))) return undefined;
423
+ var opts = Array.isArray(productOptionItem) ? productOptionItem : [];
424
+ if (opts.length !== 1) return undefined;
425
+ var o = opts[0];
426
+ var gid = Number(o === null || o === void 0 ? void 0 : o.option_group_id) || 0;
427
+ var oid = Number(o === null || o === void 0 ? void 0 : o.product_option_item_id) || 0;
428
+ var rawNum = o === null || o === void 0 ? void 0 : o.num;
429
+ var n = typeof rawNum === 'number' && !Number.isNaN(rawNum) ? Math.max(1, Math.floor(rawNum)) : 1;
430
+ return "".concat(productId, "_").concat(gid, "_").concat(oid, "_").concat(n);
431
+ }
432
+ function collectLineIdentityKeyCandidates(x) {
433
+ var _row$metadata;
434
+ var out = new Set();
435
+ var row = x;
436
+ if (typeof row.identity_key === 'string' && row.identity_key.length > 0) {
437
+ out.add(row.identity_key);
438
+ }
439
+ var uid = (_row$metadata = row.metadata) === null || _row$metadata === void 0 ? void 0 : _row$metadata.unique_identification_number;
440
+ if (typeof uid === 'string' && uid.length > 0) out.add(uid);
441
+ var synthetic = buildSyntheticSingleOptionIdentityKey(row.product_id, row.product_option_item);
442
+ if (synthetic) out.add(synthetic);
443
+ var opts = 'product_option_item' in row && Array.isArray(row.product_option_item) ? row.product_option_item : [];
444
+ var bundles = 'product_bundle' in row && Array.isArray(row.product_bundle) ? row.product_bundle : [];
445
+ // 无小料且无套餐时,与常见 UI 约定对齐:`${product_id}_${product_variant_id}_0`
446
+ if (opts.length === 0 && bundles.length === 0 && row.product_id != null && Number.isFinite(Number(row.product_id))) {
447
+ var vid = Number(row.product_variant_id) || 0;
448
+ out.add("".concat(row.product_id, "_").concat(vid, "_0"));
449
+ }
450
+ return out;
451
+ }
452
+ function fingerprintForIdentityWithOptionKeys(x) {
453
+ var row = x;
454
+ var opts = 'product_option_item' in row ? Array.isArray(row.product_option_item) ? row.product_option_item : [] : [];
455
+ var buds = 'product_bundle' in row ? Array.isArray(row.product_bundle) ? row.product_bundle : [] : [];
456
+ return buildProductLineFingerprint(opts, buds);
457
+ }
458
+
369
459
  /**
370
460
  * 判断两个商品 identity 是否匹配。
371
- * 当双方都没有 identity_key 时回退到 product_id + product_variant_id 比较(向后兼容);
372
- * 一旦有一方携带 identity_key,则必须严格相等。
461
+ * - 任一方带 `identity_key`:两侧都有则比字符串相等;仅一侧有则比「另一侧有效 key 集合」是否含该 key(见 collectLineIdentityKeyCandidates)。
462
+ * - 否则若任一方为「仅 SKU」删除通配(未声明 product_option_item / product_bundle 键),只比 SKU。
463
+ * - 否则比较选项 + 套餐指纹(同 SKU 且指纹相同才合并数量)。
373
464
  */
374
465
  export function isIdentityMatch(a, b) {
375
466
  if (a.product_id !== b.product_id || a.product_variant_id !== b.product_variant_id) return false;
376
- if (!a.identity_key && !b.identity_key) return true;
377
- return a.identity_key === b.identity_key;
467
+ if (a.identity_key || b.identity_key) {
468
+ if (a.identity_key && b.identity_key) return a.identity_key === b.identity_key;
469
+ if (a.identity_key && !b.identity_key) {
470
+ return collectLineIdentityKeyCandidates(b).has(a.identity_key);
471
+ }
472
+ if (!a.identity_key && b.identity_key) {
473
+ return collectLineIdentityKeyCandidates(a).has(b.identity_key);
474
+ }
475
+ return false;
476
+ }
477
+ if (isSkuOnlyDeleteIdentity(a) || isSkuOnlyDeleteIdentity(b)) return true;
478
+ return fingerprintForIdentityWithOptionKeys(a) === fingerprintForIdentityWithOptionKeys(b);
378
479
  }
379
480
 
380
481
  /**
@@ -414,14 +515,14 @@ export function normalizeOrderProduct(product) {
414
515
  metadata.main_product_selling_price = resolvedSellingPrice;
415
516
  }
416
517
  if (metadata.source_product_price === undefined) {
417
- var _ref, _product$_origin$pric, _product$_origin, _product$_origin2;
418
- metadata.source_product_price = (_ref = (_product$_origin$pric = (_product$_origin = product._origin) === null || _product$_origin === void 0 ? void 0 : _product$_origin.price) !== null && _product$_origin$pric !== void 0 ? _product$_origin$pric : (_product$_origin2 = product._origin) === null || _product$_origin2 === void 0 ? void 0 : _product$_origin2.base_price) !== null && _ref !== void 0 ? _ref : resolvedSellingPrice;
518
+ var _ref2, _product$_origin$pric, _product$_origin, _product$_origin2;
519
+ metadata.source_product_price = (_ref2 = (_product$_origin$pric = (_product$_origin = product._origin) === null || _product$_origin === void 0 ? void 0 : _product$_origin.price) !== null && _product$_origin$pric !== void 0 ? _product$_origin$pric : (_product$_origin2 = product._origin) === null || _product$_origin2 === void 0 ? void 0 : _product$_origin2.base_price) !== null && _ref2 !== void 0 ? _ref2 : resolvedSellingPrice;
419
520
  }
420
521
  var normalizedBundle = (product.product_bundle || []).map(function (item) {
421
- var _ref2, _item$bundle_selling_, _ref3, _ref4, _item$custom_price;
522
+ var _ref3, _item$bundle_selling_, _ref4, _ref5, _item$custom_price;
422
523
  return _objectSpread(_objectSpread({}, item), {}, {
423
- bundle_selling_price: (_ref2 = (_item$bundle_selling_ = item.bundle_selling_price) !== null && _item$bundle_selling_ !== void 0 ? _item$bundle_selling_ : item.price) !== null && _ref2 !== void 0 ? _ref2 : '0.00',
424
- custom_price: (_ref3 = (_ref4 = (_item$custom_price = item.custom_price) !== null && _item$custom_price !== void 0 ? _item$custom_price : item.bundle_selling_price) !== null && _ref4 !== void 0 ? _ref4 : item.price) !== null && _ref3 !== void 0 ? _ref3 : '0.00'
524
+ bundle_selling_price: (_ref3 = (_item$bundle_selling_ = item.bundle_selling_price) !== null && _item$bundle_selling_ !== void 0 ? _item$bundle_selling_ : item.price) !== null && _ref3 !== void 0 ? _ref3 : '0.00',
525
+ custom_price: (_ref4 = (_ref5 = (_item$custom_price = item.custom_price) !== null && _item$custom_price !== void 0 ? _item$custom_price : item.bundle_selling_price) !== null && _ref5 !== void 0 ? _ref5 : item.price) !== null && _ref4 !== void 0 ? _ref4 : '0.00'
425
526
  });
426
527
  });
427
528
  return {
@@ -580,4 +681,36 @@ export function pickFirstCustomCapacityPaxBounds(products) {
580
681
  _iterator9.f();
581
682
  }
582
683
  return undefined;
684
+ }
685
+
686
+ /**
687
+ * 第一个 `capacity.type === 'custom'` 的商品,取其 `custom[0].id`(提交 booking metadata.capacity 维度 id)。
688
+ * 无匹配时返回 `undefined`,调用方应回退为 `0`。
689
+ */
690
+ export function pickFirstCustomCapacityDimensionId(products) {
691
+ var _iterator10 = _createForOfIteratorHelper(products),
692
+ _step10;
693
+ try {
694
+ for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
695
+ var p = _step10.value;
696
+ var cap = p === null || p === void 0 ? void 0 : p.capacity;
697
+ if (!cap || cap.type !== 'custom') continue;
698
+ if (!Array.isArray(cap.custom) || cap.custom.length === 0) continue;
699
+ var row = cap.custom[0];
700
+ if (!row || _typeof(row) !== 'object') continue;
701
+ var id = row.id;
702
+ if (id === null || id === undefined || id === '') continue;
703
+ if (typeof id === 'number' && Number.isFinite(id)) return id;
704
+ if (typeof id === 'string') {
705
+ var trimmed = id.trim();
706
+ if (!trimmed) continue;
707
+ return trimmed;
708
+ }
709
+ }
710
+ } catch (err) {
711
+ _iterator10.e(err);
712
+ } finally {
713
+ _iterator10.f();
714
+ }
715
+ return undefined;
583
716
  }
@@ -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
- });
@@ -288,6 +288,18 @@ var OrderModule = class extends import_BaseModule.BaseModule {
288
288
  this.window.localStorage.removeItem(key);
289
289
  return;
290
290
  }
291
+ if (Array.isArray(parsedData.products)) {
292
+ for (const p of parsedData.products) {
293
+ if (!p || typeof p !== "object")
294
+ continue;
295
+ if (!Array.isArray(p.product_option_item)) {
296
+ p.product_option_item = [];
297
+ }
298
+ if (!Array.isArray(p.product_bundle)) {
299
+ p.product_bundle = [];
300
+ }
301
+ }
302
+ }
291
303
  this.store.tempOrder = parsedData;
292
304
  } catch {
293
305
  (_b = (_a = this.window) == null ? void 0 : _a.localStorage) == null ? void 0 : _b.removeItem(key);
@@ -444,18 +456,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
444
456
  }
445
457
  async removeProductFromOrder(identity) {
446
458
  const tempOrder = this.ensureTempOrder();
447
- const beforeProducts = tempOrder.products;
448
459
  tempOrder.products = tempOrder.products.filter(
449
460
  (item) => !(0, import_utils3.isIdentityMatch)(item, identity)
450
461
  );
451
- const removedByStrictIdentity = beforeProducts.length - tempOrder.products.length;
452
- if (removedByStrictIdentity === 0 && identity.identity_key) {
453
- tempOrder.products = tempOrder.products.filter((item) => {
454
- const isSameProduct = String(item.product_id) === String(identity.product_id) && String(item.product_variant_id) === String(identity.product_variant_id);
455
- const hasNoIdentityKey = !item.identity_key;
456
- return !(isSameProduct && hasNoIdentityKey);
457
- });
458
- }
459
462
  this.applyDiscount();
460
463
  await this.recalculateSummary({ createIfMissing: true });
461
464
  this.persistTempOrder();
@@ -477,7 +480,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
477
480
  });
478
481
  let result;
479
482
  if (tempOrder.order_id) {
480
- const products = (0, import_utils.formatV1Product)(payload.products);
483
+ let products = (0, import_utils.formatV1Product)(
484
+ (0, import_utils.filterProductsForScanOrderMore)(payload.products)
485
+ );
481
486
  const moreResult = await this.scanOrderMore({
482
487
  query: {
483
488
  order_id: tempOrder.order_id,
@@ -72,6 +72,8 @@ export declare function buildSubmitPayload(params: {
72
72
  type?: string;
73
73
  enhance?: SubmitPayloadEnhancer;
74
74
  }): ScanOrderSubmitPayload;
75
+ /** 加单(scanOrderMore)不应提交 booking 关联的虚拟规则商品行 */
76
+ export declare function filterProductsForScanOrderMore(products: ScanOrderSubmitProduct[]): ScanOrderSubmitProduct[];
75
77
  export declare function formatV1Product(products: ScanOrderSubmitProduct[]): {
76
78
  bundle: any[];
77
79
  key: number | null;
@@ -34,6 +34,7 @@ __export(utils_exports, {
34
34
  createDefaultTempOrder: () => createDefaultTempOrder,
35
35
  createEmptySummary: () => import_utils2.createEmptySummary,
36
36
  createUuidV4: () => createUuidV4,
37
+ filterProductsForScanOrderMore: () => filterProductsForScanOrderMore,
37
38
  formatDateTime: () => formatDateTime,
38
39
  formatV1Product: () => formatV1Product,
39
40
  generateDuration: () => generateDuration,
@@ -59,7 +60,12 @@ function createDefaultOrderRulesHooks() {
59
60
  var _a, _b, _c, _d;
60
61
  return {
61
62
  id: product.product_id,
62
- _id: product.identity_key ? `${product.product_id}_${product.product_variant_id}_${product.identity_key}` : `${product.product_id}_${product.product_variant_id}`,
63
+ // Rules 引擎用 _id 作为 processedProductsMap 键;必须与购物车行级 identity 一致,
64
+ // 否则同 SKU 不同小料会在 calcDiscount 重组时互相覆盖。
65
+ _id: product.identity_key ? `${product.product_id}_${product.product_variant_id}_${product.identity_key}` : `${product.product_id}_${product.product_variant_id}_${(0, import_utils.buildProductLineFingerprint)(
66
+ product.product_option_item,
67
+ product.product_bundle
68
+ )}`,
63
69
  price: product.selling_price,
64
70
  total: new import_decimal.default(product.selling_price || 0).times(product.num || 1).toNumber(),
65
71
  origin_total: new import_decimal.default(product.original_price || product.selling_price || 0).times(product.num || 1).toNumber(),
@@ -366,6 +372,12 @@ function buildSubmitPayload(params) {
366
372
  };
367
373
  return enhance ? enhance(payload, { tempOrder, bookingUuid, now }) : payload;
368
374
  }
375
+ function filterProductsForScanOrderMore(products) {
376
+ return (products || []).filter((p) => {
377
+ var _a;
378
+ return ((_a = p.metadata) == null ? void 0 : _a.is_rule) !== true;
379
+ });
380
+ }
369
381
  function formatV1Product(products) {
370
382
  return products.map((product) => {
371
383
  return {
@@ -388,6 +400,7 @@ function formatV1Product(products) {
388
400
  createDefaultTempOrder,
389
401
  createEmptySummary,
390
402
  createUuidV4,
403
+ filterProductsForScanOrderMore,
391
404
  formatDateTime,
392
405
  formatV1Product,
393
406
  generateDuration,
@@ -741,7 +741,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
741
741
  return 1;
742
742
  };
743
743
  return (payload, { bookingUuid, tempOrder }) => {
744
- var _a;
744
+ var _a, _b;
745
745
  const resourceId = tempOrder.resource_id ?? (resourceState == null ? void 0 : resourceState.relationId);
746
746
  const pickOriginal = (value) => {
747
747
  if (value && typeof value === "object" && !Array.isArray(value)) {
@@ -762,20 +762,31 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
762
762
  metadata: {}
763
763
  } : void 0;
764
764
  const ruleProductUid = ruleProduct ? (0, import_utils2.createUuidV4)() : void 0;
765
- const bookingCapacityValue = resolveResourceCapacity();
765
+ const rawCollectPax = (_b = tempOrder.metadata) == null ? void 0 : _b.collect_pax;
766
+ const hasCollectPaxForCapacity = rawCollectPax !== null && rawCollectPax !== void 0 && rawCollectPax !== "";
767
+ const bookingCapacityValue = hasCollectPaxForCapacity ? (0, import_utils2.normalizeSubmitCollectPaxValue)(rawCollectPax) : resolveResourceCapacity();
768
+ const bookingCapacityDimensionId = (0, import_utils.pickFirstCustomCapacityDimensionId)(this.enabledReservationRuleProducts) ?? 0;
766
769
  const nextBookings = (payload.bookings || []).map((booking, idx) => ({
767
770
  ...booking,
768
771
  appointment_status: "started",
769
772
  metadata: {
770
773
  ...booking.metadata || {},
771
774
  ...resourceSelectType ? { resource_select_type: resourceSelectType } : {},
772
- ...resourceSelectType ? { capacity: [{ id: 0, value: bookingCapacityValue, name: "" }] } : {}
775
+ ...resourceSelectType ? {
776
+ capacity: [
777
+ {
778
+ id: bookingCapacityDimensionId,
779
+ value: bookingCapacityValue,
780
+ name: ""
781
+ }
782
+ ]
783
+ } : {}
773
784
  },
774
785
  ...idx === 0 && resourceEntry ? { resources: [resourceEntry] } : {},
775
786
  ...idx === 0 && ruleProductUid ? { product_uid: ruleProductUid } : {}
776
787
  }));
777
788
  const nextProducts = [...payload.products || []];
778
- if (ruleProduct && ruleProductUid) {
789
+ if (ruleProduct && ruleProductUid && !tempOrder.order_id) {
779
790
  const sellingPrice = String(ruleProduct.price ?? "0.00");
780
791
  const originalPrice = String(
781
792
  ruleProduct.original_price ?? ruleProduct.price ?? "0.00"
@@ -1261,7 +1272,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
1261
1272
  const relationId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.form_record_id);
1262
1273
  const tableFormId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.form_id);
1263
1274
  const formRecord = (detail == null ? void 0 : detail.form_record) ?? null;
1264
- const allowSnack = ((_b = (_a = this.otherParams) == null ? void 0 : _a.dineInConfig) == null ? void 0 : _b["workflow.allow_add_items"]) || false;
1275
+ const allowSnack = ((_b = (_a = this.otherParams) == null ? void 0 : _a.dineInConfig) == null ? void 0 : _b["sale.allow_add_items"]) || false;
1265
1276
  const deskmateValid = false;
1266
1277
  const isExclusive = resourceSelectType === "single";
1267
1278
  const isFull = (0, import_utils.computeResourceIsFull)({
@@ -1620,10 +1631,10 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
1620
1631
  readUIStateBucket() {
1621
1632
  var _a;
1622
1633
  const key = this.getUIStateBucketKey();
1623
- if (!key || !((_a = this.window) == null ? void 0 : _a.sessionStorage))
1634
+ if (!key || !((_a = this.window) == null ? void 0 : _a.localStorage))
1624
1635
  return {};
1625
1636
  try {
1626
- const raw = this.window.sessionStorage.getItem(key) || "{}";
1637
+ const raw = this.window.localStorage.getItem(key) || "{}";
1627
1638
  const parsed = JSON.parse(raw);
1628
1639
  return parsed && typeof parsed === "object" ? parsed : {};
1629
1640
  } catch {
@@ -1633,10 +1644,10 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
1633
1644
  writeUIStateBucket(bucket) {
1634
1645
  var _a;
1635
1646
  const key = this.getUIStateBucketKey();
1636
- if (!key || !((_a = this.window) == null ? void 0 : _a.sessionStorage))
1647
+ if (!key || !((_a = this.window) == null ? void 0 : _a.localStorage))
1637
1648
  return;
1638
1649
  try {
1639
- this.window.sessionStorage.setItem(key, JSON.stringify(bucket));
1650
+ this.window.localStorage.setItem(key, JSON.stringify(bucket));
1640
1651
  } catch (error) {
1641
1652
  console.warn("[ScanOrder] writeUIStateBucket failed", error);
1642
1653
  }
@@ -1667,10 +1678,10 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
1667
1678
  clearUIState() {
1668
1679
  var _a;
1669
1680
  const key = this.getUIStateBucketKey();
1670
- if (!key || !((_a = this.window) == null ? void 0 : _a.sessionStorage))
1681
+ if (!key || !((_a = this.window) == null ? void 0 : _a.localStorage))
1671
1682
  return;
1672
1683
  try {
1673
- this.window.sessionStorage.removeItem(key);
1684
+ this.window.localStorage.removeItem(key);
1674
1685
  } catch (error) {
1675
1686
  console.warn("[ScanOrder] clearUIState failed", error);
1676
1687
  }
@@ -1726,11 +1737,18 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
1726
1737
  };
1727
1738
  var ScanOrderImpl = _ScanOrderImpl;
1728
1739
  ScanOrderImpl.PISELL1_LOGIN_SUCCESS = "pisell1.login.success";
1729
- // ─── UI 状态缓存(按 cacheId 分桶,sessionStorage) ───
1740
+ // ─── UI 状态缓存(按 cacheId 分桶,localStorage) ───
1730
1741
  //
1731
1742
  // 用于物料层持久化 UI 层面的轻量状态(如当前步骤、gate 标记、登录回跳意图等)。
1732
1743
  // 桶键:pisell.scanOrder.uiState:<cacheId>;内部以 JSON object 形式存储多个字段。
1733
1744
  // 无 cacheId 时所有方法自动降级为 no-op,上层不用判空。
1745
+ //
1746
+ // 之所以用 localStorage 而不是 sessionStorage:
1747
+ // 1. 与 Order 模块 openCache 下的 tempOrder 同栈,购物车在 / UIState 在,行为对齐;
1748
+ // 2. pisell1.login 整页 OAuth 跳转在 H5 壳 / iOS Safari 场景下可能丢 sessionStorage,
1749
+ // 导致登录回跳后 gate 标记失效、pax 弹窗重开、落点错误;localStorage 稳定不受影响。
1750
+ // 3. 失效由上层显式控制:提交成功 clearStepCache / entryContext 不一致 clearUIState /
1751
+ // pendingStep 登录回调 deleteUIState,足够约束生命周期。
1734
1752
  ScanOrderImpl.UI_STATE_KEY_PREFIX = "pisell.scanOrder.uiState:";
1735
1753
  // Annotate the CommonJS export names for ESM import in node:
1736
1754
  0 && (module.exports = {
@@ -31,6 +31,9 @@ export interface ScanOrderOrderProductIdentity {
31
31
  product_id: number | null;
32
32
  product_variant_id: number;
33
33
  identity_key?: string;
34
+ /** 参与合并/匹配;与 remove 通配语义见 isSkuOnlyDeleteIdentity */
35
+ product_option_item?: any[];
36
+ product_bundle?: any[];
34
37
  }
35
38
  export interface ScanOrderOrderProduct extends ScanOrderOrderProductIdentity {
36
39
  order_detail_id: number | null;
@@ -81,10 +81,27 @@ export declare function buildItemRuleBusinessData(params: {
81
81
  itemRuleConfigs: StrategyConfig[];
82
82
  }): ItemRuleBusinessData;
83
83
  export declare function attachItemRuleLimitsToTopLevelProducts<T>(productList: T, limits: QuantityLimitResult[]): T;
84
+ /**
85
+ * 将选项行 / 套餐行归一成稳定 JSON,用于「同 SKU 是否合并」判断。
86
+ * 数组元素先按主键排序再序列化,避免顺序差异导致误判为不同行。
87
+ */
88
+ export declare function buildProductLineFingerprint(productOptionItem?: unknown, productBundle?: unknown): string;
89
+ /**
90
+ * removeProductFromOrder 仅传 SKU 时的通配 identity(对象上未声明选项键)。
91
+ * 与显式 `product_option_item: []` 区分:后者只匹配「无选项」行。
92
+ */
93
+ export declare function isSkuOnlyDeleteIdentity(x: ScanOrderOrderProductIdentity): boolean;
94
+ /**
95
+ * 与常见 UI 约定一致:仅当存在**一条** `product_option_item` 时,
96
+ * `${product_id}_${option_group_id}_${product_option_item_id}_${num}` 可作为删除用 `identity_key`。
97
+ * 多小料行请使用加购时的 `identity_key` / `metadata.unique_identification_number` 或按 `product_option_item` 指纹删除。
98
+ */
99
+ export declare function buildSyntheticSingleOptionIdentityKey(productId: number | null, productOptionItem: unknown): string | undefined;
84
100
  /**
85
101
  * 判断两个商品 identity 是否匹配。
86
- * 当双方都没有 identity_key 时回退到 product_id + product_variant_id 比较(向后兼容);
87
- * 一旦有一方携带 identity_key,则必须严格相等。
102
+ * - 任一方带 `identity_key`:两侧都有则比字符串相等;仅一侧有则比「另一侧有效 key 集合」是否含该 key(见 collectLineIdentityKeyCandidates)。
103
+ * - 否则若任一方为「仅 SKU」删除通配(未声明 product_option_item / product_bundle 键),只比 SKU。
104
+ * - 否则比较选项 + 套餐指纹(同 SKU 且指纹相同才合并数量)。
88
105
  */
89
106
  export declare function isIdentityMatch(a: ScanOrderOrderProductIdentity, b: ScanOrderOrderProductIdentity): boolean;
90
107
  /**
@@ -129,3 +146,8 @@ export declare function pickFirstCustomCapacityPaxBounds(products: ProductData[]
129
146
  min?: number;
130
147
  max?: number;
131
148
  } | undefined;
149
+ /**
150
+ * 第一个 `capacity.type === 'custom'` 的商品,取其 `custom[0].id`(提交 booking metadata.capacity 维度 id)。
151
+ * 无匹配时返回 `undefined`,调用方应回退为 `0`。
152
+ */
153
+ export declare function pickFirstCustomCapacityDimensionId(products: ProductData[]): string | number | undefined;
@@ -33,7 +33,9 @@ __export(utils_exports, {
33
33
  attachItemRuleLimitsToTopLevelProducts: () => attachItemRuleLimitsToTopLevelProducts,
34
34
  buildItemRuleBusinessData: () => buildItemRuleBusinessData,
35
35
  buildProductKey: () => buildProductKey,
36
+ buildProductLineFingerprint: () => buildProductLineFingerprint,
36
37
  buildQuantityLimitIndex: () => buildQuantityLimitIndex,
38
+ buildSyntheticSingleOptionIdentityKey: () => buildSyntheticSingleOptionIdentityKey,
37
39
  collectLinkProductIdsFromReservationRules: () => collectLinkProductIdsFromReservationRules,
38
40
  computeResourceIsFull: () => computeResourceIsFull,
39
41
  createEmptySummary: () => createEmptySummary,
@@ -44,9 +46,11 @@ __export(utils_exports, {
44
46
  getTopLevelVariantId: () => getTopLevelVariantId,
45
47
  hasCustomCapacityProduct: () => hasCustomCapacityProduct,
46
48
  isIdentityMatch: () => isIdentityMatch,
49
+ isSkuOnlyDeleteIdentity: () => isSkuOnlyDeleteIdentity,
47
50
  normalizeEnabledItemRuleIds: () => normalizeEnabledItemRuleIds,
48
51
  normalizeItemRuleStrategies: () => normalizeItemRuleStrategies,
49
52
  normalizeOrderProduct: () => normalizeOrderProduct,
53
+ pickFirstCustomCapacityDimensionId: () => pickFirstCustomCapacityDimensionId,
50
54
  pickFirstCustomCapacityPaxBounds: () => pickFirstCustomCapacityPaxBounds,
51
55
  pickFirstDurationMinutesFromProducts: () => pickFirstDurationMinutesFromProducts,
52
56
  resolveSkuMatchedQuantityLimits: () => resolveSkuMatchedQuantityLimits,
@@ -338,12 +342,102 @@ function attachItemRuleLimitsToTopLevelProducts(productList, limits) {
338
342
  }
339
343
  return productList;
340
344
  }
345
+ function buildProductLineFingerprint(productOptionItem, productBundle) {
346
+ const optArr = Array.isArray(productOptionItem) ? productOptionItem : [];
347
+ const normalizedOpts = optArr.map((item) => ({
348
+ product_option_item_id: Number(item == null ? void 0 : item.product_option_item_id) || 0,
349
+ option_group_id: Number(item == null ? void 0 : item.option_group_id) || 0,
350
+ num: typeof (item == null ? void 0 : item.num) === "number" && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1,
351
+ price: String((item == null ? void 0 : item.price) ?? "")
352
+ })).sort((p, q) => {
353
+ if (p.product_option_item_id !== q.product_option_item_id) {
354
+ return p.product_option_item_id - q.product_option_item_id;
355
+ }
356
+ if (p.option_group_id !== q.option_group_id)
357
+ return p.option_group_id - q.option_group_id;
358
+ if (p.num !== q.num)
359
+ return p.num - q.num;
360
+ return p.price.localeCompare(q.price);
361
+ });
362
+ const bundleArr = Array.isArray(productBundle) ? productBundle : [];
363
+ const normalizedBundles = bundleArr.map((item) => ({
364
+ bundle_id: Number((item == null ? void 0 : item.bundle_id) ?? (item == null ? void 0 : item.id) ?? 0) || 0,
365
+ product_id: Number(item == null ? void 0 : item.product_id) || 0,
366
+ num: typeof (item == null ? void 0 : item.num) === "number" && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1
367
+ })).sort((p, q) => {
368
+ if (p.bundle_id !== q.bundle_id)
369
+ return p.bundle_id - q.bundle_id;
370
+ if (p.product_id !== q.product_id)
371
+ return p.product_id - q.product_id;
372
+ return p.num - q.num;
373
+ });
374
+ return JSON.stringify([normalizedOpts, normalizedBundles]);
375
+ }
376
+ function isSkuOnlyDeleteIdentity(x) {
377
+ if (x.identity_key)
378
+ return false;
379
+ return !("product_option_item" in x) && !("product_bundle" in x);
380
+ }
381
+ function buildSyntheticSingleOptionIdentityKey(productId, productOptionItem) {
382
+ if (productId == null || !Number.isFinite(Number(productId)))
383
+ return void 0;
384
+ const opts = Array.isArray(productOptionItem) ? productOptionItem : [];
385
+ if (opts.length !== 1)
386
+ return void 0;
387
+ const o = opts[0];
388
+ const gid = Number(o == null ? void 0 : o.option_group_id) || 0;
389
+ const oid = Number(o == null ? void 0 : o.product_option_item_id) || 0;
390
+ const rawNum = o == null ? void 0 : o.num;
391
+ const n = typeof rawNum === "number" && !Number.isNaN(rawNum) ? Math.max(1, Math.floor(rawNum)) : 1;
392
+ return `${productId}_${gid}_${oid}_${n}`;
393
+ }
394
+ function collectLineIdentityKeyCandidates(x) {
395
+ var _a;
396
+ const out = /* @__PURE__ */ new Set();
397
+ const row = x;
398
+ if (typeof row.identity_key === "string" && row.identity_key.length > 0) {
399
+ out.add(row.identity_key);
400
+ }
401
+ const uid = (_a = row.metadata) == null ? void 0 : _a.unique_identification_number;
402
+ if (typeof uid === "string" && uid.length > 0)
403
+ out.add(uid);
404
+ const synthetic = buildSyntheticSingleOptionIdentityKey(
405
+ row.product_id,
406
+ row.product_option_item
407
+ );
408
+ if (synthetic)
409
+ out.add(synthetic);
410
+ const opts = "product_option_item" in row && Array.isArray(row.product_option_item) ? row.product_option_item : [];
411
+ const bundles = "product_bundle" in row && Array.isArray(row.product_bundle) ? row.product_bundle : [];
412
+ if (opts.length === 0 && bundles.length === 0 && row.product_id != null && Number.isFinite(Number(row.product_id))) {
413
+ const vid = Number(row.product_variant_id) || 0;
414
+ out.add(`${row.product_id}_${vid}_0`);
415
+ }
416
+ return out;
417
+ }
418
+ function fingerprintForIdentityWithOptionKeys(x) {
419
+ const row = x;
420
+ const opts = "product_option_item" in row ? Array.isArray(row.product_option_item) ? row.product_option_item : [] : [];
421
+ const buds = "product_bundle" in row ? Array.isArray(row.product_bundle) ? row.product_bundle : [] : [];
422
+ return buildProductLineFingerprint(opts, buds);
423
+ }
341
424
  function isIdentityMatch(a, b) {
342
425
  if (a.product_id !== b.product_id || a.product_variant_id !== b.product_variant_id)
343
426
  return false;
344
- if (!a.identity_key && !b.identity_key)
427
+ if (a.identity_key || b.identity_key) {
428
+ if (a.identity_key && b.identity_key)
429
+ return a.identity_key === b.identity_key;
430
+ if (a.identity_key && !b.identity_key) {
431
+ return collectLineIdentityKeyCandidates(b).has(a.identity_key);
432
+ }
433
+ if (!a.identity_key && b.identity_key) {
434
+ return collectLineIdentityKeyCandidates(a).has(b.identity_key);
435
+ }
436
+ return false;
437
+ }
438
+ if (isSkuOnlyDeleteIdentity(a) || isSkuOnlyDeleteIdentity(b))
345
439
  return true;
346
- return a.identity_key === b.identity_key;
440
+ return fingerprintForIdentityWithOptionKeys(a) === fingerprintForIdentityWithOptionKeys(b);
347
441
  }
348
442
  function getProductIdentityIndex(products, identity) {
349
443
  return products.findIndex((item) => isIdentityMatch(item, identity));
@@ -474,13 +568,39 @@ function pickFirstCustomCapacityPaxBounds(products) {
474
568
  }
475
569
  return void 0;
476
570
  }
571
+ function pickFirstCustomCapacityDimensionId(products) {
572
+ for (const p of products) {
573
+ const cap = p == null ? void 0 : p.capacity;
574
+ if (!cap || cap.type !== "custom")
575
+ continue;
576
+ if (!Array.isArray(cap.custom) || cap.custom.length === 0)
577
+ continue;
578
+ const row = cap.custom[0];
579
+ if (!row || typeof row !== "object")
580
+ continue;
581
+ const id = row.id;
582
+ if (id === null || id === void 0 || id === "")
583
+ continue;
584
+ if (typeof id === "number" && Number.isFinite(id))
585
+ return id;
586
+ if (typeof id === "string") {
587
+ const trimmed = id.trim();
588
+ if (!trimmed)
589
+ continue;
590
+ return trimmed;
591
+ }
592
+ }
593
+ return void 0;
594
+ }
477
595
  // Annotate the CommonJS export names for ESM import in node:
478
596
  0 && (module.exports = {
479
597
  aggregateItemRuleLimit,
480
598
  attachItemRuleLimitsToTopLevelProducts,
481
599
  buildItemRuleBusinessData,
482
600
  buildProductKey,
601
+ buildProductLineFingerprint,
483
602
  buildQuantityLimitIndex,
603
+ buildSyntheticSingleOptionIdentityKey,
484
604
  collectLinkProductIdsFromReservationRules,
485
605
  computeResourceIsFull,
486
606
  createEmptySummary,
@@ -491,9 +611,11 @@ function pickFirstCustomCapacityPaxBounds(products) {
491
611
  getTopLevelVariantId,
492
612
  hasCustomCapacityProduct,
493
613
  isIdentityMatch,
614
+ isSkuOnlyDeleteIdentity,
494
615
  normalizeEnabledItemRuleIds,
495
616
  normalizeItemRuleStrategies,
496
617
  normalizeOrderProduct,
618
+ pickFirstCustomCapacityDimensionId,
497
619
  pickFirstCustomCapacityPaxBounds,
498
620
  pickFirstDurationMinutesFromProducts,
499
621
  resolveSkuMatchedQuantityLimits,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "0.0.508",
4
+ "version": "0.0.510",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",