@pisell/pisellos 2.1.108 → 2.1.110

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,4 +1,8 @@
1
+ var _excluded = ["_original_add_price"],
2
+ _excluded2 = ["_original_price", "_original_add_price"];
1
3
  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); }
4
+ function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
5
+ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
2
6
  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; }
3
7
  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; }
4
8
  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; } } }; }
@@ -146,7 +150,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
146
150
  if (productList.every(function (item) {
147
151
  var _product$discount_lis;
148
152
  var product = _this2.hooks.getProduct(item);
149
- return product.booking_id && (((_product$discount_lis = product.discount_list) === null || _product$discount_lis === void 0 ? void 0 : _product$discount_lis.length) || (newDiscountList[0].tag === 'good_pass' ? product.price == 0 : product.total == 0));
153
+ return product.booking_id && (((_product$discount_lis = product.discount_list) === null || _product$discount_lis === void 0 ? void 0 : _product$discount_lis.length) || product.total == 0);
150
154
  })) {
151
155
  return {
152
156
  isAvailable: false,
@@ -301,13 +305,6 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
301
305
  holders = _ref2.holders,
302
306
  isFormSubject = _ref2.isFormSubject,
303
307
  orderTotalAmount = _ref2.orderTotalAmount;
304
- // 识别出来是不是在编辑的界面里又新增了商品
305
- // 这种情况下,如果有可用的优惠券,也会自动勾选上
306
- var isEditModeAddNewProduct = productList.find(function (n) {
307
- return n.booking_id;
308
- }) && productList.find(function (n) {
309
- return !n.booking_id;
310
- });
311
308
  var editModeDiscount = [];
312
309
  var addModeDiscount = [];
313
310
  discountList.forEach(function (discount) {
@@ -521,6 +518,14 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
521
518
  // 🔥 扁平化商品列表(包含主商品和bundle子商品)
522
519
  var flattenedList = flattenProductsWithBundle(productList);
523
520
 
521
+ // 识别出来是不是在编辑的界面里又新增了商品
522
+ // 这种情况下,如果有可用的优惠券,也会自动勾选上
523
+ var isEditModeAddNewProduct = flattenedList.find(function (n) {
524
+ return n.booking_id;
525
+ }) && flattenedList.find(function (n) {
526
+ return !n.booking_id;
527
+ });
528
+
524
529
  // 对扁平化后的列表按价格降序排序(用于应用优惠券时优先选择高价商品)
525
530
  var sortedFlattenedList = flattenedList.sort(function (a, b) {
526
531
  var _ref3, _a$original_price, _ref4, _b$original_price;
@@ -570,11 +575,13 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
570
575
 
571
576
  // 转换 sortedFlattenedList 为 Product 格式
572
577
  var productsForEvaluate = sortedFlattenedList.map(function (item) {
578
+ var _item$product;
573
579
  return {
574
580
  product_id: item.id,
575
581
  price: item.price || 0,
576
582
  quantity: item.quantity || item.num || 1,
577
- selling_price: item.price || 0
583
+ selling_price: item.price || 0,
584
+ product_options: item.type === 'main' ? (_item$product = item.product) === null || _item$product === void 0 ? void 0 : _item$product.options : undefined
578
585
  };
579
586
  });
580
587
 
@@ -600,8 +607,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
600
607
  }
601
608
 
602
609
  /**
603
- // 对productList按价格降序排序(用于应用优惠券时优先选择高价商品) 价格相同时使用quantity 排序
604
- const sortedProductList = [...productList].sort((a, b) => {
610
+ // 对productList按价格降序排序(用于应用优惠券时优先选择高价商品) 价格相同时使用quantity 排序
611
+ const sortedProductList = [...productList].sort((a, b) => {
605
612
  const aProduct = this.hooks.getProduct(a);
606
613
  const bProduct = this.hooks.getProduct(b);
607
614
  const priceA = new Decimal((aProduct.price as string) || '0');
@@ -850,6 +857,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
850
857
  var _flatItem$parentProdu5;
851
858
  // bundle子商品:构造虚拟商品对象
852
859
  product = {
860
+ startDate: flatItem === null || flatItem === void 0 || (_flatItem$parentProdu5 = flatItem.parentProduct) === null || _flatItem$parentProdu5 === void 0 ? void 0 : _flatItem$parentProdu5.startDate,
853
861
  _id: flatItem._id,
854
862
  id: flatItem.id,
855
863
  price: flatItem.price,
@@ -858,8 +866,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
858
866
  total: flatItem.total,
859
867
  origin_total: flatItem.origin_total,
860
868
  booking_id: flatItem.booking_id,
861
- discount_list: flatItem.discount_list || [],
862
- startDate: (_flatItem$parentProdu5 = flatItem.parentProduct) === null || _flatItem$parentProdu5 === void 0 ? void 0 : _flatItem$parentProdu5.startDate
869
+ discount_list: flatItem.discount_list || []
863
870
  };
864
871
  originProduct = flatItem.originProduct;
865
872
  }
@@ -929,6 +936,61 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
929
936
  // 🔥 用于存储扁平化商品处理结果的Map
930
937
  var processedFlatItemsMap = new Map();
931
938
 
939
+ // 🔥 Option 折扣辅助函数
940
+ var applyDiscountToOptions = function applyDiscountToOptions(options, discount) {
941
+ if (!(options !== null && options !== void 0 && options.length)) return {
942
+ discountedOptions: options,
943
+ optionDiscountAmount: 0
944
+ };
945
+ var optionDiscountAmount = 0;
946
+ var discountedOptions = options.map(function (option) {
947
+ var _ref6, _ref7, _option$_original_pri, _ref8, _option$num, _rest$price, _option$_original_pri2;
948
+ // 折前单价:优先 price,缺失再 add_price;已写回折后价时用 _original_price(或旧字段 _original_add_price)
949
+ var rawUnit = (_ref6 = (_ref7 = (_option$_original_pri = option._original_price) !== null && _option$_original_pri !== void 0 ? _option$_original_pri : option._original_add_price) !== null && _ref7 !== void 0 ? _ref7 : option.price) !== null && _ref6 !== void 0 ? _ref6 : option.add_price;
950
+ var baseUnitNum = Number(rawUnit !== null && rawUnit !== void 0 ? rawUnit : 0);
951
+ if (baseUnitNum <= 0) return option;
952
+ var discountedPrice = getDiscountAmount(discount, baseUnitNum, baseUnitNum);
953
+ var optQty = Number((_ref8 = (_option$num = option.num) !== null && _option$num !== void 0 ? _option$num : option.quantity) !== null && _ref8 !== void 0 ? _ref8 : 1);
954
+ optionDiscountAmount = new Decimal(optionDiscountAmount).plus(new Decimal(baseUnitNum).minus(discountedPrice).mul(optQty)).toNumber();
955
+ var _original_add_price = option._original_add_price,
956
+ rest = _objectWithoutProperties(option, _excluded);
957
+ var tmpl = (_rest$price = rest.price) !== null && _rest$price !== void 0 ? _rest$price : rest.add_price;
958
+ var nextPrice = typeof tmpl === 'string' ? String(discountedPrice) : discountedPrice;
959
+ return _objectSpread(_objectSpread({}, rest), {}, {
960
+ _original_price: (_option$_original_pri2 = option._original_price) !== null && _option$_original_pri2 !== void 0 ? _option$_original_pri2 : _original_add_price !== undefined ? _original_add_price : rawUnit,
961
+ price: nextPrice
962
+ });
963
+ });
964
+ return {
965
+ discountedOptions: discountedOptions,
966
+ optionDiscountAmount: optionDiscountAmount
967
+ };
968
+ };
969
+ var restoreOptionPrices = function restoreOptionPrices(options) {
970
+ if (!(options !== null && options !== void 0 && options.length)) return options;
971
+ return options.map(function (option) {
972
+ var orig = option._original_price !== undefined ? option._original_price : option._original_add_price;
973
+ if (orig !== undefined) {
974
+ var _original_price = option._original_price,
975
+ _original_add_price = option._original_add_price,
976
+ rest = _objectWithoutProperties(option, _excluded2);
977
+ return _objectSpread(_objectSpread({}, rest), {}, {
978
+ price: orig
979
+ });
980
+ }
981
+ return option;
982
+ });
983
+ };
984
+ var getOptionTotal = function getOptionTotal(options) {
985
+ if (!(options !== null && options !== void 0 && options.length)) return 0;
986
+ return options.reduce(function (sum, opt) {
987
+ var _ref9, _opt$price, _ref10, _opt$num;
988
+ var unit = Number((_ref9 = (_opt$price = opt.price) !== null && _opt$price !== void 0 ? _opt$price : opt.add_price) !== null && _ref9 !== void 0 ? _ref9 : 0);
989
+ var n = Number((_ref10 = (_opt$num = opt.num) !== null && _opt$num !== void 0 ? _opt$num : opt.quantity) !== null && _ref10 !== void 0 ? _ref10 : 1);
990
+ return new Decimal(sum).plus(new Decimal(unit).mul(n)).toNumber();
991
+ }, 0);
992
+ };
993
+
932
994
  // 然后再处理应用哪些优惠券,此时只考虑filteredDiscountList中的优惠券
933
995
  // 🔥 使用扁平化后的列表进行处理
934
996
  sortedFlattenedList.forEach(function (flatItem, index) {
@@ -939,9 +1001,10 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
939
1001
  product = flatItem.product;
940
1002
  originProduct = flatItem.originProduct;
941
1003
  } else {
942
- var _flatItem$bundleItem5, _flatItem$bundleItem6, _flatItem$bundleItem7, _flatItem$parentProdu6;
1004
+ var _flatItem$parentProdu6, _flatItem$bundleItem5, _flatItem$bundleItem6, _flatItem$bundleItem7;
943
1005
  // bundle子商品
944
1006
  product = {
1007
+ startDate: flatItem === null || flatItem === void 0 || (_flatItem$parentProdu6 = flatItem.parentProduct) === null || _flatItem$parentProdu6 === void 0 ? void 0 : _flatItem$parentProdu6.startDate,
945
1008
  _id: flatItem._id,
946
1009
  id: flatItem.id,
947
1010
  price: flatItem.price,
@@ -951,8 +1014,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
951
1014
  original_price: flatItem === null || flatItem === void 0 || (_flatItem$bundleItem5 = flatItem.bundleItem) === null || _flatItem$bundleItem5 === void 0 ? void 0 : _flatItem$bundleItem5.original_price,
952
1015
  origin_total: flatItem === null || flatItem === void 0 || (_flatItem$bundleItem6 = flatItem.bundleItem) === null || _flatItem$bundleItem6 === void 0 ? void 0 : _flatItem$bundleItem6.original_price,
953
1016
  booking_id: flatItem.booking_id,
954
- discount_list: (flatItem === null || flatItem === void 0 || (_flatItem$bundleItem7 = flatItem.bundleItem) === null || _flatItem$bundleItem7 === void 0 ? void 0 : _flatItem$bundleItem7.discount_list) || [],
955
- startDate: (_flatItem$parentProdu6 = flatItem.parentProduct) === null || _flatItem$parentProdu6 === void 0 ? void 0 : _flatItem$parentProdu6.startDate
1017
+ discount_list: (flatItem === null || flatItem === void 0 || (_flatItem$bundleItem7 = flatItem.bundleItem) === null || _flatItem$bundleItem7 === void 0 ? void 0 : _flatItem$bundleItem7.discount_list) || []
956
1018
  };
957
1019
  originProduct = flatItem.originProduct;
958
1020
  }
@@ -1022,11 +1084,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1022
1084
  }
1023
1085
  }
1024
1086
  var limitedData = discount.limited_relation_product_data;
1025
- var timeLimit = true;
1026
- timeLimit = !!filterDiscountListByBookingTime([discount], (product.startDate || dayjs()).format('YYYY-MM-DD HH:mm:ss')).length;
1027
- if (!timeLimit) {
1028
- return false;
1029
- }
1087
+
1030
1088
  // 拿到discount配置的holder信息 product信息 product.holder 不可用return false
1031
1089
  var _tempVar = (flatItem === null || flatItem === void 0 ? void 0 : flatItem.type) === 'bundle' ? flatItem === null || flatItem === void 0 ? void 0 : flatItem.parentProduct : flatItem === null || flatItem === void 0 ? void 0 : flatItem.product;
1032
1090
  var isHolderMatch = _this3.checkHolderMatch(discount, {
@@ -1035,6 +1093,11 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1035
1093
  }, holders);
1036
1094
  // 如果 holder 不匹配,则不适用
1037
1095
  if (!isHolderMatch) return false;
1096
+ var timeLimit = true;
1097
+ timeLimit = !!filterDiscountListByBookingTime([discount], (product.startDate || dayjs()).format('YYYY-MM-DD HH:mm:ss')).length;
1098
+ if (!timeLimit) {
1099
+ return false;
1100
+ }
1038
1101
 
1039
1102
  // 判断优惠券是否适用于该商品
1040
1103
  if (limitedData.type === 'product_all') {
@@ -1070,19 +1133,22 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1070
1133
  var _product$discount_lis5, _product12, _product12$every;
1071
1134
  // 主商品:判断自身是否手动折扣
1072
1135
  isManualDiscount = typeof product.isManualDiscount === 'boolean' ? product.isManualDiscount : product.total != product.origin_total && (product.bundle || []).every(function (item) {
1073
- var _ref6;
1074
- return !((_ref6 = item.discount_list || []) !== null && _ref6 !== void 0 && _ref6.length);
1136
+ var _ref11;
1137
+ return !((_ref11 = item.discount_list || []) !== null && _ref11 !== void 0 && _ref11.length);
1075
1138
  }) && (!((_product$discount_lis5 = product.discount_list) !== null && _product$discount_lis5 !== void 0 && _product$discount_lis5.length) || ((_product12 = product) === null || _product12 === void 0 || (_product12 = _product12.discount_list) === null || _product12 === void 0 || (_product12$every = _product12.every) === null || _product12$every === void 0 ? void 0 : _product12$every.call(_product12, function (item) {
1076
1139
  return item.type === 'product';
1077
1140
  })));
1141
+ if (product.inPromotion) {
1142
+ isManualDiscount = false;
1143
+ }
1078
1144
  } else {
1079
1145
  // bundle子商品:判断父主商品是否手动折扣
1080
1146
  var parentProduct = flatItem.parentProduct;
1081
1147
  if (parentProduct) {
1082
1148
  var _parentProduct$discou, _parentProduct$discou2, _parentProduct$discou3;
1083
1149
  isManualDiscount = typeof parentProduct.isManualDiscount === 'boolean' ? parentProduct.isManualDiscount : parentProduct.total != parentProduct.origin_total && (parentProduct.bundle || []).every(function (item) {
1084
- var _ref7;
1085
- return !((_ref7 = item.discount_list || []) !== null && _ref7 !== void 0 && _ref7.length);
1150
+ var _ref12;
1151
+ return !((_ref12 = item.discount_list || []) !== null && _ref12 !== void 0 && _ref12.length);
1086
1152
  }) && (!((_parentProduct$discou = parentProduct.discount_list) !== null && _parentProduct$discou !== void 0 && _parentProduct$discou.length) || (parentProduct === null || parentProduct === void 0 || (_parentProduct$discou2 = parentProduct.discount_list) === null || _parentProduct$discou2 === void 0 || (_parentProduct$discou3 = _parentProduct$discou2.every) === null || _parentProduct$discou3 === void 0 ? void 0 : _parentProduct$discou3.call(_parentProduct$discou2, function (item) {
1087
1153
  return item.type === 'product';
1088
1154
  })));
@@ -1149,7 +1215,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1149
1215
  // 如果没有适用的优惠券,或者手动折扣,则不适用优惠券
1150
1216
  if (applicableDiscounts.length === 0 || isManualDiscount || isBoolean(product.vouchersApplicable) && !product.vouchersApplicable) {
1151
1217
  if (flatItem.type === 'main') {
1152
- // 主商品:保持原有逻辑
1218
+ // 主商品:保持原有逻辑,还原 option 价格
1219
+ var restoredOptions = restoreOptionPrices(product.options);
1153
1220
  if (product.isClient) {
1154
1221
  processedProductsMap.set(product._id, [_this3.hooks.setProduct(originProduct, _objectSpread(_objectSpread({}, isManualDiscount ? {} : {
1155
1222
  origin_total: getProductOriginTotalPrice({
@@ -1157,7 +1224,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1157
1224
  original_price: product.original_price
1158
1225
  },
1159
1226
  bundle: product.bundle,
1160
- options: product.options
1227
+ options: restoredOptions
1161
1228
  }),
1162
1229
  variant: originProduct._productInit.variant,
1163
1230
  original_price: originProduct._productInit.original_price,
@@ -1166,15 +1233,16 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1166
1233
  price: product.price
1167
1234
  },
1168
1235
  bundle: product.bundle,
1169
- options: product.options
1236
+ options: restoredOptions
1170
1237
  }),
1171
- price: product.price
1238
+ price: product.price,
1239
+ options: restoredOptions
1172
1240
  }), {}, {
1173
1241
  discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion')
1174
1242
  }))]);
1175
1243
  } else {
1176
- var _ref8, _product$_promotion$f, _product13, _product$origin_total, _product$price2;
1177
- var total = product.inPromotion ? (_ref8 = (_product$_promotion$f = (_product13 = product) === null || _product13 === void 0 || (_product13 = _product13._promotion) === null || _product13 === void 0 ? void 0 : _product13.finalPrice) !== null && _product$_promotion$f !== void 0 ? _product$_promotion$f : product.origin_total) !== null && _ref8 !== void 0 ? _ref8 : product.total : (_product$origin_total = product.origin_total) !== null && _product$origin_total !== void 0 ? _product$origin_total : product.total;
1244
+ var _ref13, _product$_promotion$f, _product13, _product$origin_total, _product$price2;
1245
+ var total = product.inPromotion ? (_ref13 = (_product$_promotion$f = (_product13 = product) === null || _product13 === void 0 || (_product13 = _product13._promotion) === null || _product13 === void 0 ? void 0 : _product13.finalPrice) !== null && _product$_promotion$f !== void 0 ? _product$_promotion$f : product.origin_total) !== null && _ref13 !== void 0 ? _ref13 : product.total : (_product$origin_total = product.origin_total) !== null && _product$origin_total !== void 0 ? _product$origin_total : product.total;
1178
1246
  var main_product_selling_price = (_product$price2 = product.price) !== null && _product$price2 !== void 0 ? _product$price2 : product.main_product_selling_price;
1179
1247
  if ((product.discount_list || []).some(function (item) {
1180
1248
  return item.type === 'promotion';
@@ -1189,7 +1257,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1189
1257
  _id: product._id.split('___')[0] + '___' + index,
1190
1258
  total: total,
1191
1259
  price: product.price,
1192
- main_product_selling_price: main_product_selling_price
1260
+ main_product_selling_price: main_product_selling_price,
1261
+ options: restoredOptions
1193
1262
  }), {}, {
1194
1263
  discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion')
1195
1264
  }))]);
@@ -1248,15 +1317,23 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1248
1317
  if (flatItem.type === 'main') {
1249
1318
  // 主商品:保持原有逻辑
1250
1319
  if (splitCount < totalQuantity && isNeedSplit) {
1320
+ var _product$origin_total2;
1321
+ var _total = (_product$origin_total2 = product.origin_total) !== null && _product$origin_total2 !== void 0 ? _product$origin_total2 : product.total;
1322
+ if ((product.discount_list || []).some(function (item) {
1323
+ return item.type === 'promotion';
1324
+ })) {
1325
+ var _product$total2;
1326
+ _total = (_product$total2 = product.total) !== null && _product$total2 !== void 0 ? _product$total2 : product.origin_total;
1327
+ }
1251
1328
  arr.push(_this3.hooks.setProduct(originProduct, {
1252
1329
  discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion'),
1253
1330
  quantity: totalQuantity - splitCount,
1254
1331
  _id: product._id.split('___')[0],
1255
- total: product.origin_total || product.total
1332
+ total: _total
1256
1333
  }));
1257
1334
  }
1258
1335
  for (var i = 0; i < splitCount; i++) {
1259
- var _originProduct, _currentSelectedDisco, _currentSelectedDisco2;
1336
+ var _originProduct, _selectedDiscount$con2, _product$options, _product$options2, _selectedDiscount$met, _selectedDiscount$met2;
1260
1337
  // 商品券:每个拆分商品使用不同的商品券(从 applicableDiscounts 按索引取)
1261
1338
  // 折扣卡:所有拆分商品使用同一张折扣卡(selectedDiscountCard 或 applicableDiscounts[0])
1262
1339
  var currentSelectedDiscount = isGoodPass ? selectedDiscountCard || applicableDiscounts[i] : selectedDiscountCard || applicableDiscounts[0];
@@ -1293,33 +1370,50 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1293
1370
  var isOrderLevel = isOrderLevelFixedAmountDiscount(selectedDiscount);
1294
1371
  var orderLevelAllocation = isOrderLevel ? orderLevelDiscountAllocations.get(selectedDiscount.id) : null;
1295
1372
  var productAllocation = orderLevelAllocation === null || orderLevelAllocation === void 0 ? void 0 : orderLevelAllocation.get(flatItem._id);
1296
- var targetProductTotal = void 0;
1373
+ var isDeductOptionPrice = !!((_selectedDiscount$con2 = selectedDiscount.config) !== null && _selectedDiscount$con2 !== void 0 && _selectedDiscount$con2.deductOptionPrice);
1374
+
1375
+ // 主商品折后价(不含 option);勿与 option 合计混在同一变量,否则 main_product_selling_price 错误
1376
+ var mainProductSellingPrice = void 0;
1297
1377
  var amount = void 0;
1298
1378
  var productDiscountDifference = void 0;
1379
+ var discountedOptions = product.options;
1380
+ var optionDiscountAmount = 0;
1299
1381
  if (isOrderLevel && productAllocation) {
1300
1382
  // order_level:使用预计算的分摊金额
1301
1383
  amount = productAllocation.discountAmount;
1302
1384
  productDiscountDifference = productAllocation.difference;
1303
- targetProductTotal = Math.max(new Decimal(product.price).minus(amount).toNumber(), 0);
1385
+ mainProductSellingPrice = Math.max(new Decimal(product.price).minus(amount).toNumber(), 0);
1304
1386
  } else {
1305
1387
  // item_level 或其他类型:使用原有逻辑
1306
- targetProductTotal = getDiscountAmount(currentSelectedDiscount, product.price, product.price);
1307
- amount = new Decimal(product.price).minus(new Decimal(targetProductTotal)).toNumber();
1388
+ mainProductSellingPrice = getDiscountAmount(currentSelectedDiscount, product.price, product.price);
1389
+ amount = new Decimal(product.price).minus(new Decimal(mainProductSellingPrice)).toNumber();
1390
+ }
1391
+ if (isDeductOptionPrice && (_product$options = product.options) !== null && _product$options !== void 0 && _product$options.length) {
1392
+ var optionResult = applyDiscountToOptions(product.options, currentSelectedDiscount);
1393
+ discountedOptions = optionResult.discountedOptions;
1394
+ optionDiscountAmount = optionResult.optionDiscountAmount;
1308
1395
  }
1309
- var currentDiscountType = currentSelectedDiscount.tag === 'product_discount_card' ? 'discount_card' : currentSelectedDiscount.tag;
1310
1396
 
1311
- // 计算实际折扣金额
1312
- var actualDiscountAmount = new Decimal(product.price).minus(new Decimal(targetProductTotal)).toNumber();
1397
+ // total = 主商品折后 + option 行合计;开启 option 抵扣时必须用 discountedOptions,不能用未折扣的 product.options 再算一遍
1398
+ var optionsForLineTotal = isDeductOptionPrice && (_product$options2 = product.options) !== null && _product$options2 !== void 0 && _product$options2.length ? discountedOptions : product.options;
1399
+ var optionsLineTotal = getOptionTotal(optionsForLineTotal || []);
1400
+ var _total2 = new Decimal(mainProductSellingPrice).plus(optionsLineTotal).toNumber();
1401
+
1402
+ // discount_list.amount / fixed_amount:行级总优惠 = 主商品优惠 + option 优惠(与 total 变化一致)
1403
+ var mainProductDiscountAmount = amount;
1404
+ var lineDiscountAmount = new Decimal(mainProductDiscountAmount).plus(optionDiscountAmount).toNumber();
1405
+ var currentDiscountType = currentSelectedDiscount.tag === 'product_discount_card' ? 'discount_card' : currentSelectedDiscount.tag;
1406
+ var _discountType = selectedDiscount.tag || selectedDiscount.type;
1313
1407
  var currentIsGoodPass = currentDiscountType === 'good_pass';
1314
1408
  var discountDetail = {
1315
- amount: actualDiscountAmount,
1316
- type: currentDiscountType,
1409
+ amount: lineDiscountAmount,
1410
+ type: selectedDiscount.tag === 'product_discount_card' ? 'discount_card' : _discountType,
1317
1411
  discount: {
1318
- discount_card_type: currentSelectedDiscount === null || currentSelectedDiscount === void 0 || (_currentSelectedDisco = currentSelectedDiscount.metadata) === null || _currentSelectedDisco === void 0 ? void 0 : _currentSelectedDisco.discount_card_type,
1319
- fixed_amount: actualDiscountAmount,
1320
- discount_calculation_mode: currentSelectedDiscount === null || currentSelectedDiscount === void 0 || (_currentSelectedDisco2 = currentSelectedDiscount.metadata) === null || _currentSelectedDisco2 === void 0 ? void 0 : _currentSelectedDisco2.discount_calculation_mode,
1321
- resource_id: currentSelectedDiscount.id,
1322
- title: currentSelectedDiscount.format_title,
1412
+ discount_card_type: selectedDiscount === null || selectedDiscount === void 0 || (_selectedDiscount$met = selectedDiscount.metadata) === null || _selectedDiscount$met === void 0 ? void 0 : _selectedDiscount$met.discount_card_type,
1413
+ fixed_amount: lineDiscountAmount,
1414
+ discount_calculation_mode: selectedDiscount === null || selectedDiscount === void 0 || (_selectedDiscount$met2 = selectedDiscount.metadata) === null || _selectedDiscount$met2 === void 0 ? void 0 : _selectedDiscount$met2.discount_calculation_mode,
1415
+ resource_id: selectedDiscount.id,
1416
+ title: selectedDiscount.format_title,
1323
1417
  original_amount: product.price,
1324
1418
  product_id: originProduct.id,
1325
1419
  percent: currentSelectedDiscount.par_value,
@@ -1328,41 +1422,39 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1328
1422
  // 前端使用的num数量,为了计算优惠金额(拆分时为1)
1329
1423
  _num: isNeedSplit ? 1 : product.num,
1330
1424
  config: currentSelectedDiscount === null || currentSelectedDiscount === void 0 ? void 0 : currentSelectedDiscount.config,
1331
- metadata: _objectSpread({
1425
+ metadata: _objectSpread(_objectSpread({
1332
1426
  num: 1,
1333
1427
  discount_rule_uncheck_flag: selectedDiscount === null || selectedDiscount === void 0 ? void 0 : selectedDiscount.discount_rule_uncheck_flag
1334
1428
  }, productDiscountDifference !== undefined && {
1335
1429
  product_discount_difference: productDiscountDifference
1430
+ }), {}, {
1431
+ /** 仅主商品上的优惠金额(不含 option) */
1432
+ mainProductDiscountAmount: mainProductDiscountAmount,
1433
+ optionDiscountAmount: optionDiscountAmount
1336
1434
  })
1337
1435
  };
1338
1436
  appliedProducts.push(discountDetail);
1339
1437
  appliedDiscountProducts.set(currentSelectedDiscount.id, appliedProducts);
1340
- var _total = targetProductTotal;
1341
- if (product.options) {
1342
- _total = product.options.reduce(function (accumulator, currentValue) {
1343
- var currentPrice = new Decimal(currentValue.price || 0);
1344
- var currentNum = new Decimal(currentValue.num || 0);
1345
- return accumulator.add(currentPrice.mul(currentNum));
1346
- }, new Decimal(_total)).toNumber();
1347
- }
1348
1438
 
1349
1439
  // 记录应用了优惠券的商品
1350
1440
  // 后续更新价格改为 getProductTotalPrice getProductOriginTotalPrice逻辑
1351
1441
  if (product.isClient) {
1352
1442
  arr.push(_this3.hooks.setProduct(originProduct, {
1353
1443
  discount_list: [discountDetail],
1354
- price: currentIsGoodPass ? product.price - discountDetail.amount : product.price,
1444
+ // good_pass:主商品价以折后价为准;勿用 product.price - amount(amount option 优惠时会算错)
1445
+ price: currentIsGoodPass ? mainProductSellingPrice : product.price,
1355
1446
  quantity: isNeedSplit ? 1 : product.quantity,
1356
1447
  origin_total: getProductOriginTotalPrice({
1357
1448
  product: {
1358
1449
  original_price: product.original_price
1359
1450
  },
1360
1451
  bundle: product.bundle,
1361
- options: product.options
1452
+ options: restoreOptionPrices(product.options)
1362
1453
  }),
1363
1454
  variant: originProduct._productInit.variant,
1364
1455
  original_price: new Decimal(product.price || 0).toNumber(),
1365
- total: targetProductTotal
1456
+ total: _total2,
1457
+ options: discountedOptions
1366
1458
  }));
1367
1459
  } else {
1368
1460
  arr.push(_this3.hooks.setProduct(originProduct, {
@@ -1370,9 +1462,10 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1370
1462
  _id: product._id.split('___')[0] + '___' + currentSelectedDiscount.id + '_' + i + '_' + index,
1371
1463
  price: currentIsGoodPass ? 0 : product.price,
1372
1464
  quantity: isNeedSplit ? 1 : product.quantity,
1373
- total: targetProductTotal,
1465
+ total: _total2,
1374
1466
  origin_total: productOriginTotal,
1375
- main_product_selling_price: targetProductTotal
1467
+ main_product_selling_price: mainProductSellingPrice,
1468
+ options: discountedOptions
1376
1469
  }));
1377
1470
  }
1378
1471
  }
@@ -1709,22 +1802,22 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1709
1802
  var _isOrderLevel = isOrderLevelFixedAmountDiscount(selectedDiscount);
1710
1803
  var _orderLevelAllocation = _isOrderLevel ? orderLevelDiscountAllocations.get(selectedDiscount.id) : null;
1711
1804
  var _productAllocation = _orderLevelAllocation === null || _orderLevelAllocation === void 0 ? void 0 : _orderLevelAllocation.get(flatItem._id);
1712
- var _targetProductTotal;
1805
+ var targetProductTotal;
1713
1806
  var fixedAmountPerItem;
1714
1807
  var _productDiscountDifference;
1715
1808
  if (_isOrderLevel && _productAllocation) {
1716
1809
  // order_level:使用预计算的单价折扣金额(已经是单价,无需再除以数量)
1717
1810
  fixedAmountPerItem = _productAllocation.discountAmount;
1718
1811
  _productDiscountDifference = _productAllocation.difference;
1719
- _targetProductTotal = Math.max(new Decimal(_productOriginTotal).minus(fixedAmountPerItem).toNumber(), 0);
1812
+ targetProductTotal = Math.max(new Decimal(_productOriginTotal).minus(fixedAmountPerItem).toNumber(), 0);
1720
1813
  } else {
1721
1814
  // item_level 或其他类型:使用原有逻辑
1722
- _targetProductTotal = getDiscountAmount(_currentBundleDiscount, _productOriginTotal, _productOriginTotal);
1723
- fixedAmountPerItem = new Decimal(_productOriginTotal).minus(_targetProductTotal).toNumber();
1815
+ targetProductTotal = getDiscountAmount(_currentBundleDiscount, _productOriginTotal, _productOriginTotal);
1816
+ fixedAmountPerItem = new Decimal(_productOriginTotal).minus(targetProductTotal).toNumber();
1724
1817
  }
1725
1818
 
1726
1819
  // 计算实际折扣金额
1727
- var bundleActualDiscountAmount = new Decimal(_productOriginTotal).minus(_targetProductTotal).toNumber();
1820
+ var bundleActualDiscountAmount = new Decimal(_productOriginTotal).minus(targetProductTotal).toNumber();
1728
1821
 
1729
1822
  // 🔥 使用当前的 _id 作为唯一标识
1730
1823
  var _uniqueId = flatItem._id;
@@ -1759,7 +1852,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1759
1852
  _appliedProducts2.push(_discountDetail2);
1760
1853
  appliedDiscountProducts.set(_currentBundleDiscount.id, _appliedProducts2);
1761
1854
  processedItems.push(_objectSpread(_objectSpread({}, flatItem), {}, {
1762
- total: _targetProductTotal,
1855
+ total: targetProductTotal,
1763
1856
  price: new Decimal(_productOriginTotal || 0).minus(fixedAmountPerItem).toNumber(),
1764
1857
  discount_list: _this3.filterDiscountListByType(flatItem.discount_list, 'promotion').concat([_discountDetail2]),
1765
1858
  processed: true
@@ -1778,8 +1871,9 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1778
1871
  // 获取主商品处理结果
1779
1872
  var mainProductArr = processedProductsMap.get(product._id);
1780
1873
  if (!mainProductArr || mainProductArr.length === 0) {
1781
- // 如果没有处理结果,返回默认商品
1874
+ // 如果没有处理结果,返回默认商品(还原 option 价格)
1782
1875
  var getDefaultProduct = function getDefaultProduct() {
1876
+ var restoredOptions = restoreOptionPrices(product.options);
1783
1877
  if (product.isClient) {
1784
1878
  return _this3.hooks.setProduct(originProduct, {
1785
1879
  discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion'),
@@ -1789,7 +1883,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1789
1883
  original_price: product.original_price
1790
1884
  },
1791
1885
  bundle: product.bundle,
1792
- options: product.options
1886
+ options: restoredOptions
1793
1887
  }),
1794
1888
  variant: originProduct._productInit.variant,
1795
1889
  original_price: originProduct._productInit.original_price,
@@ -1798,15 +1892,17 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1798
1892
  price: product.price
1799
1893
  },
1800
1894
  bundle: product.bundle,
1801
- options: product.options
1802
- })
1895
+ options: restoredOptions
1896
+ }),
1897
+ options: restoredOptions
1803
1898
  });
1804
1899
  } else {
1805
1900
  return _this3.hooks.setProduct(originProduct, {
1806
1901
  discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion'),
1807
1902
  total: product.total,
1808
1903
  origin_total: product.origin_total,
1809
- price: product.price
1904
+ price: product.price,
1905
+ options: restoreOptionPrices(product.options)
1810
1906
  });
1811
1907
  }
1812
1908
  };
@@ -2086,7 +2182,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
2086
2182
  price: item.price,
2087
2183
  num: item.num,
2088
2184
  quantity: item.num,
2089
- discount_list: updatedDiscountList
2185
+ discount_list: updatedDiscountList,
2186
+ bundle_selling_price: bundleItem.bundle_selling_price !== undefined ? item.price : undefined
2090
2187
  }));
2091
2188
  });
2092
2189
  }
@@ -67,6 +67,7 @@ export interface RulesParamsHooks {
67
67
  quantity?: number;
68
68
  bundle?: any[];
69
69
  main_product_selling_price?: string | number;
70
+ options?: any[];
70
71
  }) => Record<string, any>;
71
72
  }
72
73
  export {};
@@ -358,7 +358,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
358
358
  };
359
359
  setOtherData(key: string, value: any): void;
360
360
  getOtherData(key: string): any;
361
- getProductTypeById(id: number): Promise<"duration" | "session" | "normal">;
361
+ getProductTypeById(id: number): Promise<"normal" | "duration" | "session">;
362
362
  /**
363
363
  * 提供给 UI 的方法,减轻 UI 层的计算压力,UI 层只需要传递 cartItemId 和 resourceCode 即返回对应的 renderList
364
364
  *
@@ -42,7 +42,8 @@ var defaultStrategyMetadataCustom = {
42
42
  allowCrossProduct: true,
43
43
  applicableProductLimit: 0,
44
44
  deductTaxAndFee: true,
45
- maxPassesPerItem: 0
45
+ maxPassesPerItem: 0,
46
+ deductOptionPrice: false
46
47
  };
47
48
  var WalletPassEvaluator = class {
48
49
  constructor() {
@@ -43,6 +43,8 @@ export interface Voucher {
43
43
  applicableProductLimit: number;
44
44
  /** 单订单行每单位可用同一 Wallet Pass 券次数;该行总券次上限 = maxPassesPerItem × 该行 quantity(按行唯一键区分)。0 表示不限制。 */
45
45
  maxPassesPerItem: number;
46
+ /** 是否抵扣单规格价格 (Option Price),默认 false。开启后折扣范围包含 option 的 add_price */
47
+ deductOptionPrice: boolean;
46
48
  };
47
49
  }
48
50
  /**
@@ -62,6 +64,13 @@ export interface Product {
62
64
  main_product_original_price?: number;
63
65
  /** 主商品折扣后金额,不包含套餐子商品 */
64
66
  main_product_selling_price?: number;
67
+ /** 单规格(Option)列表 */
68
+ product_options?: {
69
+ id: number;
70
+ add_price: number | string;
71
+ num: number;
72
+ [key: string]: any;
73
+ }[];
65
74
  /** 主商品税费 */
66
75
  tax_fee: number;
67
76
  metadata: {
@@ -138,6 +147,8 @@ export interface EvaluatorInput {
138
147
  applicableProductLimit: number;
139
148
  /** 单订单行每单位可用同一 Wallet Pass 券次数;行总上限 = maxPassesPerItem × 该行 quantity(按行唯一键计)。0 表示不限制。 */
140
149
  maxPassesPerItem: number;
150
+ /** 是否抵扣单规格价格 (Option Price),默认 false */
151
+ deductOptionPrice: boolean;
141
152
  }>[];
142
153
  }
143
154
  /**