@pisell/pisellos 2.1.59 → 2.1.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +1 -0
  3. package/dist/model/index.d.ts +1 -0
  4. package/dist/model/index.js +1 -0
  5. package/dist/model/strategy/adapter/index.d.ts +3 -0
  6. package/dist/model/strategy/adapter/index.js +4 -0
  7. package/dist/model/strategy/adapter/type.d.ts +28 -0
  8. package/dist/model/strategy/adapter/type.js +1 -0
  9. package/dist/model/strategy/adapter/walletPass/evaluator.d.ts +84 -0
  10. package/dist/model/strategy/adapter/walletPass/evaluator.js +496 -0
  11. package/dist/model/strategy/adapter/walletPass/example.d.ts +4 -0
  12. package/dist/model/strategy/adapter/walletPass/example.js +258 -0
  13. package/dist/model/strategy/adapter/walletPass/index.d.ts +32 -0
  14. package/dist/model/strategy/adapter/walletPass/index.js +182 -0
  15. package/dist/model/strategy/adapter/walletPass/locales.d.ts +1 -0
  16. package/dist/model/strategy/adapter/walletPass/locales.js +23 -0
  17. package/dist/model/strategy/adapter/walletPass/type.d.ts +163 -0
  18. package/dist/model/strategy/adapter/walletPass/type.js +1 -0
  19. package/dist/model/strategy/adapter/walletPass/utils.d.ts +50 -0
  20. package/dist/model/strategy/adapter/walletPass/utils.js +965 -0
  21. package/dist/model/strategy/index.d.ts +94 -0
  22. package/dist/model/strategy/index.js +551 -0
  23. package/dist/model/strategy/strategy-example.d.ts +5 -0
  24. package/dist/model/strategy/strategy-example.js +331 -0
  25. package/dist/model/strategy/type.d.ts +228 -0
  26. package/dist/model/strategy/type.js +94 -0
  27. package/dist/modules/Cart/types.d.ts +2 -0
  28. package/dist/modules/Cart/utils/cartProduct.js +11 -0
  29. package/dist/modules/Discount/types.d.ts +15 -0
  30. package/dist/modules/Payment/index.d.ts +2 -1
  31. package/dist/modules/Payment/index.js +10 -7
  32. package/dist/modules/Payment/utils.js +3 -0
  33. package/dist/modules/Payment/walletpass.d.ts +23 -0
  34. package/dist/modules/Payment/walletpass.js +191 -95
  35. package/dist/modules/Rules/index.d.ts +8 -3
  36. package/dist/modules/Rules/index.js +152 -26
  37. package/dist/modules/Rules/types.d.ts +1 -0
  38. package/dist/modules/Summary/types.d.ts +2 -0
  39. package/dist/modules/Summary/utils.d.ts +6 -0
  40. package/dist/modules/Summary/utils.js +21 -0
  41. package/dist/plugins/window.d.ts +2 -0
  42. package/dist/solution/BookingByStep/index.d.ts +2 -1
  43. package/dist/solution/Checkout/index.js +2 -0
  44. package/dist/solution/ShopDiscount/index.d.ts +1 -0
  45. package/dist/solution/ShopDiscount/index.js +11 -1
  46. package/dist/solution/ShopDiscount/types.d.ts +1 -0
  47. package/dist/solution/ShopDiscount/utils.js +26 -11
  48. package/lib/index.d.ts +1 -0
  49. package/lib/index.js +3 -1
  50. package/lib/model/index.d.ts +1 -0
  51. package/lib/model/index.js +23 -0
  52. package/lib/model/strategy/adapter/index.d.ts +3 -0
  53. package/lib/model/strategy/adapter/index.js +45 -0
  54. package/lib/model/strategy/adapter/type.d.ts +28 -0
  55. package/lib/model/strategy/adapter/type.js +17 -0
  56. package/lib/model/strategy/adapter/walletPass/evaluator.d.ts +84 -0
  57. package/lib/model/strategy/adapter/walletPass/evaluator.js +420 -0
  58. package/lib/model/strategy/adapter/walletPass/example.d.ts +4 -0
  59. package/lib/model/strategy/adapter/walletPass/example.js +207 -0
  60. package/lib/model/strategy/adapter/walletPass/index.d.ts +32 -0
  61. package/lib/model/strategy/adapter/walletPass/index.js +142 -0
  62. package/lib/model/strategy/adapter/walletPass/locales.d.ts +1 -0
  63. package/lib/model/strategy/adapter/walletPass/locales.js +51 -0
  64. package/lib/model/strategy/adapter/walletPass/type.d.ts +163 -0
  65. package/lib/model/strategy/adapter/walletPass/type.js +17 -0
  66. package/lib/model/strategy/adapter/walletPass/utils.d.ts +50 -0
  67. package/lib/model/strategy/adapter/walletPass/utils.js +660 -0
  68. package/lib/model/strategy/index.d.ts +94 -0
  69. package/lib/model/strategy/index.js +413 -0
  70. package/lib/model/strategy/strategy-example.d.ts +5 -0
  71. package/lib/model/strategy/strategy-example.js +318 -0
  72. package/lib/model/strategy/type.d.ts +228 -0
  73. package/lib/model/strategy/type.js +44 -0
  74. package/lib/modules/Cart/types.d.ts +2 -0
  75. package/lib/modules/Cart/utils/cartProduct.js +9 -0
  76. package/lib/modules/Discount/types.d.ts +15 -0
  77. package/lib/modules/Payment/index.d.ts +2 -1
  78. package/lib/modules/Payment/index.js +1 -0
  79. package/lib/modules/Payment/utils.js +3 -0
  80. package/lib/modules/Payment/walletpass.d.ts +23 -0
  81. package/lib/modules/Payment/walletpass.js +94 -17
  82. package/lib/modules/Rules/index.d.ts +8 -3
  83. package/lib/modules/Rules/index.js +370 -192
  84. package/lib/modules/Rules/types.d.ts +1 -0
  85. package/lib/modules/Summary/types.d.ts +2 -0
  86. package/lib/modules/Summary/utils.d.ts +6 -0
  87. package/lib/modules/Summary/utils.js +15 -0
  88. package/lib/plugins/window.d.ts +2 -0
  89. package/lib/solution/BookingByStep/index.d.ts +2 -1
  90. package/lib/solution/Checkout/index.js +2 -0
  91. package/lib/solution/ShopDiscount/index.d.ts +1 -0
  92. package/lib/solution/ShopDiscount/index.js +6 -0
  93. package/lib/solution/ShopDiscount/types.d.ts +1 -0
  94. package/lib/solution/ShopDiscount/utils.js +10 -6
  95. package/package.json +1 -1
@@ -24,12 +24,11 @@ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key i
24
24
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
25
25
  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); }
26
26
  import { BaseModule } from "../BaseModule";
27
- import { uniqueById, getDiscountAmount, filterDiscountListByBookingTime, getDiscountListAmountTotal, getDiscountListAmount } from "../../solution/ShopDiscount/utils";
27
+ import { uniqueById, getDiscountAmount, getDiscountListAmountTotal, getDiscountListAmount, filterDiscountListByBookingTime } from "../../solution/ShopDiscount/utils";
28
28
  import { getProductOriginTotalPrice, getProductTotalPrice } from "../Cart/utils";
29
29
  import Decimal from 'decimal.js';
30
30
  import { isBoolean } from 'lodash-es';
31
31
  import dayjs from 'dayjs';
32
-
33
32
  // 临时变量
34
33
  var flatItem;
35
34
  export var RulesModule = /*#__PURE__*/function (_BaseModule) {
@@ -42,6 +41,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
42
41
  _defineProperty(_assertThisInitialized(_this), "defaultName", 'rules');
43
42
  _defineProperty(_assertThisInitialized(_this), "defaultVersion", '1.0.0');
44
43
  _defineProperty(_assertThisInitialized(_this), "store", void 0);
44
+ _defineProperty(_assertThisInitialized(_this), "window", void 0);
45
+ // WindowPlugin 实例
45
46
  _defineProperty(_assertThisInitialized(_this), "hooks", void 0);
46
47
  _this.hooks = {};
47
48
  return _this;
@@ -56,7 +57,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
56
57
  this.core = core;
57
58
  this.hooks = options === null || options === void 0 ? void 0 : options.hooks;
58
59
  this.store = options === null || options === void 0 ? void 0 : options.store;
59
- case 3:
60
+ this.window = core.getPlugin('window');
61
+ case 4:
60
62
  case "end":
61
63
  return _context.stop();
62
64
  }
@@ -93,6 +95,12 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
93
95
  value: function getRulesList() {
94
96
  return this.store.rulesList;
95
97
  }
98
+ }, {
99
+ key: "getWalletPassEvaluator",
100
+ value: function getWalletPassEvaluator() {
101
+ var _this$window$getWalle, _this$window;
102
+ return (_this$window$getWalle = (_this$window = this.window).getWalletPassEvaluator) === null || _this$window$getWalle === void 0 ? void 0 : _this$window$getWalle.call(_this$window);
103
+ }
96
104
 
97
105
  // 商品不需要holder,则不需要判断,直接返回true,商品需要holder但是还没填写,那么暂时不使用带有holder的券,直到填写才去匹配
98
106
  }, {
@@ -122,6 +130,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
122
130
  newDiscountList = _ref.newDiscountList,
123
131
  productList = _ref.productList,
124
132
  holders = _ref.holders,
133
+ orderTotalAmount = _ref.orderTotalAmount,
125
134
  isFormSubject = _ref.isFormSubject;
126
135
  // 首先检查是否有新的优惠券可应用
127
136
  if (!newDiscountList || newDiscountList.length === 0) {
@@ -154,6 +163,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
154
163
  discountList: mergedDiscountList,
155
164
  productList: _toConsumableArray(productList),
156
165
  holders: holders,
166
+ orderTotalAmount: orderTotalAmount,
157
167
  isFormSubject: isFormSubject
158
168
  }, {
159
169
  scan: true
@@ -198,6 +208,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
198
208
  var discountList = _ref2.discountList,
199
209
  productList = _ref2.productList,
200
210
  holders = _ref2.holders,
211
+ orderTotalAmount = _ref2.orderTotalAmount,
201
212
  isFormSubject = _ref2.isFormSubject;
202
213
  // 识别出来是不是在编辑的界面里又新增了商品
203
214
  // 这种情况下,如果有可用的优惠券,也会自动勾选上
@@ -372,6 +383,57 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
372
383
  return priceB.minus(priceA).toNumber();
373
384
  });
374
385
 
386
+ // 🔥 为每个折扣卡/商品券执行策略检查并附加config
387
+ var evaluator = this.getWalletPassEvaluator();
388
+ if (evaluator) {
389
+ addModeDiscount.forEach(function (discount) {
390
+ var discountType = discount.tag || discount.type;
391
+ // 只对 good_pass 和 discount_card 类型执行策略检查
392
+ if (['good_pass', 'discount_card', 'product_discount_card'].includes(discountType)) {
393
+ var _discount$limited_rel, _discount$limited_rel2;
394
+ // 转换 discount 为 Voucher 格式
395
+ var voucher = {
396
+ id: discount.id,
397
+ amount: Number(discount.par_value || 0),
398
+ balance: Number(discount.balance || 0),
399
+ type: discountType,
400
+ product_id: discount.product_id,
401
+ unified_available_status: 1,
402
+ available_product_type: (_discount$limited_rel = discount.limited_relation_product_data) === null || _discount$limited_rel === void 0 ? void 0 : _discount$limited_rel.type,
403
+ available_product_ids: (_discount$limited_rel2 = discount.limited_relation_product_data) === null || _discount$limited_rel2 === void 0 ? void 0 : _discount$limited_rel2.product_ids
404
+ };
405
+
406
+ // 转换 sortedFlattenedList 为 Product 格式
407
+ var productsForEvaluate = sortedFlattenedList.map(function (item) {
408
+ return {
409
+ product_id: item.id,
410
+ price: item.price || 0,
411
+ quantity: item.quantity || item.num || 1,
412
+ selling_price: item.price || 0
413
+ };
414
+ });
415
+
416
+ // 调用策略检查
417
+ var result = evaluator.checkVoucherAvailability({
418
+ orderTotalAmount: orderTotalAmount,
419
+ products: productsForEvaluate,
420
+ vouchers: [voucher]
421
+ });
422
+
423
+ // 将 config 附加到 discount 对象
424
+ if (result.isAvailable) {
425
+ discount.config = _objectSpread(_objectSpread({}, result.config), {}, {
426
+ isAvailable: true
427
+ });
428
+ } else {
429
+ discount.config = {
430
+ isAvailable: false
431
+ };
432
+ }
433
+ }
434
+ });
435
+ }
436
+
375
437
  /**
376
438
  // 对productList按价格降序排序(用于应用优惠券时优先选择高价商品) 价格相同时使用quantity 排序
377
439
  const sortedProductList = [...productList].sort((a, b) => {
@@ -392,6 +454,9 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
392
454
  // 标记已使用的优惠券
393
455
  var usedDiscounts = new Map();
394
456
 
457
+ // 🔥 统计每个 product_id(商品券商品id)已使用的数量,用于 maxUsagePerOrder 限制
458
+ var usedProductIdCounts = new Map();
459
+
395
460
  // 记录每个优惠券适用的商品ID
396
461
  var discountApplicability = new Map();
397
462
 
@@ -434,7 +499,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
434
499
  originProduct = flatItem.originProduct;
435
500
  }
436
501
  addModeDiscount.forEach(function (discount) {
437
- var _product, _product2, _product3, _product4, _flatItem$bundleItem;
502
+ var _product, _product2, _product3, _product4, _flatItem$bundleItem, _discount$config;
438
503
  var limitedData = discount === null || discount === void 0 ? void 0 : discount.limited_relation_product_data;
439
504
  // 拿到discount配置的holder信息 product信息 product.holder 加在 isLimitedProduct
440
505
  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;
@@ -445,7 +510,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
445
510
  var timeLimit = true;
446
511
  timeLimit = !!filterDiscountListByBookingTime([discount], (((_product = product) === null || _product === void 0 ? void 0 : _product.startDate) || dayjs()).format('YYYY-MM-DD HH:mm:ss')).length;
447
512
  // 是符合折扣的商品
448
- var isLimitedProduct = (limitedData.type === 'product_all' || limitedData.product_ids && limitedData.product_ids.includes(product.id)) && isHolderMatch;
513
+ var isLimitedProduct = (limitedData.type === 'product_all' && limitedData.filter !== 1 || limitedData.type === 'product_all' && limitedData.filter === 1 && !limitedData.exclude_product_ids.includes(product.id) || limitedData.product_ids && limitedData.product_ids.includes(product.id)) && isHolderMatch;
449
514
 
450
515
  // 编辑的商品 使用了优惠券不可用
451
516
  var isAvailableProduct = flatItem.type === 'main' ? !((_product2 = product) !== null && _product2 !== void 0 && _product2.booking_id && (_product3 = product) !== null && _product3 !== void 0 && (_product3 = _product3.discount_list) !== null && _product3 !== void 0 && _product3.length && (_product4 = product) !== null && _product4 !== void 0 && (_product4 = _product4.discount_list) !== null && _product4 !== void 0 && _product4.every(function (discount) {
@@ -456,7 +521,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
456
521
  var isBundleAvailable = _this3.checkPackageSubItemUsageRules(discount, flatItem);
457
522
 
458
523
  // 判断优惠券是否适用于该商品
459
- if (isAvailableProduct && isLimitedProduct && timeLimit && isBundleAvailable) {
524
+ if (isAvailableProduct && isLimitedProduct && timeLimit && isBundleAvailable && (_discount$config = discount.config) !== null && _discount$config !== void 0 && _discount$config.isAvailable) {
460
525
  var _discountApplicabilit, _discount$metadata;
461
526
  // 记录此优惠券适用的商品
462
527
  (_discountApplicabilit = discountApplicability.get(discount.id)) === null || _discountApplicabilit === void 0 || _discountApplicabilit.push(product.id);
@@ -479,7 +544,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
479
544
  title: discount.format_title,
480
545
  original_amount: product.price || product.origin_total,
481
546
  pre_value: discount.par_value,
482
- product_id: originProduct.id
547
+ product_id: originProduct.id,
548
+ discount_product_id: discount.product_id
483
549
  },
484
550
  metadata: {
485
551
  num: num
@@ -538,6 +604,16 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
538
604
  // 找到适用于此商品的所有优惠券,仅考虑isSelected不为false的优惠券
539
605
  var applicableDiscounts = sortedDiscountList.filter(function (discount) {
540
606
  var _product$discount_lis3, _product$discount_lis4;
607
+ // 🔥 检查策略可用性(针对 good_pass 和折扣卡)
608
+ var discountType = discount.tag || discount.type;
609
+ if (['good_pass', 'discount_card', 'product_discount_card'].includes(discountType)) {
610
+ var _discount$config2;
611
+ // 如果策略检查后没有config,说明不可用
612
+ if (discount.config === undefined || !(discount !== null && discount !== void 0 && (_discount$config2 = discount.config) !== null && _discount$config2 !== void 0 && _discount$config2.isAvailable)) {
613
+ return false;
614
+ }
615
+ }
616
+
541
617
  // 如果商品价格为 0,其实不需要使用任何优惠券,直接 return true
542
618
  // 商品券时主商品价格为0不可用
543
619
  if ((Number(product.price) <= 0 || !product.price) && !((_product$discount_lis3 = product.discount_list) !== null && _product$discount_lis3 !== void 0 && _product$discount_lis3.find(function (n) {
@@ -553,6 +629,18 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
553
629
  // 如果优惠券已被使用,则跳过
554
630
  var targetUsedDiscounts = usedDiscounts.get(discount.id);
555
631
  if (targetUsedDiscounts && (discount.tag || discount.type) === 'good_pass') return false;
632
+
633
+ // 🔥 检查 maxUsagePerOrder 限制:同一 product_id 的商品券使用数量不能超过配置值
634
+ if ((discount.tag || discount.type) === 'good_pass') {
635
+ var _discount$config3;
636
+ var maxUsagePerOrder = (_discount$config3 = discount.config) === null || _discount$config3 === void 0 ? void 0 : _discount$config3.maxUsagePerOrder;
637
+ if (maxUsagePerOrder && maxUsagePerOrder > 0) {
638
+ var currentUsedCount = usedProductIdCounts.get(discount.product_id) || 0;
639
+ if (currentUsedCount >= maxUsagePerOrder) {
640
+ return false;
641
+ }
642
+ }
643
+ }
556
644
  var limitedData = discount.limited_relation_product_data;
557
645
 
558
646
  // 拿到discount配置的holder信息 product信息 product.holder 不可用return false
@@ -571,6 +659,9 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
571
659
 
572
660
  // 判断优惠券是否适用于该商品
573
661
  if (limitedData.type === 'product_all') {
662
+ if (limitedData.filter === 1 && limitedData.exclude_product_ids.includes(product.id)) {
663
+ return false;
664
+ }
574
665
  // 检查 package_sub_item_usage_rules
575
666
  if (!_this3.checkPackageSubItemUsageRules(discount, flatItem)) {
576
667
  return false;
@@ -737,7 +828,13 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
737
828
  var availableGoodPassCount = applicableDiscounts.filter(function (item) {
738
829
  return (item.tag || item.type) === 'good_pass';
739
830
  }).length;
740
- var splitCount = isNeedSplit ? Math.min(totalQuantity, availableGoodPassCount) : 1;
831
+
832
+ // 🔥 如果selectedDiscount有config配置,则使用config.maxUsagePerOrder限制使用次数
833
+ var maxUsageLimit = availableGoodPassCount;
834
+ if (selectedDiscount.config && selectedDiscount.config.maxUsagePerOrder) {
835
+ maxUsageLimit = Math.min(availableGoodPassCount, selectedDiscount.config.maxUsagePerOrder);
836
+ }
837
+ var splitCount = isNeedSplit ? Math.min(product.quantity || product.num || 1, maxUsageLimit) : 1;
741
838
  var arr = [];
742
839
 
743
840
  // 🔥 主商品和bundle子商品分别处理
@@ -747,7 +844,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
747
844
  arr.push(_this3.hooks.setProduct(originProduct, {
748
845
  discount_list: [],
749
846
  quantity: totalQuantity - splitCount,
750
- _id: product._id.split('___')[0]
847
+ _id: product._id.split('___')[0],
848
+ total: product.origin_total || product.total
751
849
  }));
752
850
  }
753
851
  for (var i = 0; i < splitCount; i++) {
@@ -756,6 +854,11 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
756
854
  var _selectedDiscount = selectedDiscountCard || applicableDiscounts[i];
757
855
  // 标记优惠券为已使用
758
856
  usedDiscounts.set(_selectedDiscount.id, true);
857
+ // 🔥 更新 product_id 使用计数
858
+ if ((_selectedDiscount.tag || _selectedDiscount.type) === 'good_pass') {
859
+ var currentCount = usedProductIdCounts.get(_selectedDiscount.product_id) || 0;
860
+ usedProductIdCounts.set(_selectedDiscount.product_id, currentCount + 1);
861
+ }
759
862
 
760
863
  // 记录实际应用了优惠券的商品信息
761
864
  var appliedProducts = appliedDiscountProducts.get(_selectedDiscount.id) || [];
@@ -773,23 +876,27 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
773
876
 
774
877
  // 计算使用折扣卡/商品券以后,单个商品的总 total
775
878
  var targetProductTotal = getDiscountAmount(_selectedDiscount, product.price, product.price);
776
- var discountType = _selectedDiscount.tag || _selectedDiscount.type;
879
+ var discountType = _selectedDiscount.tag === 'product_discount_card' ? 'discount_card' : _selectedDiscount.tag;
880
+
881
+ // 计算实际折扣金额
882
+ var actualDiscountAmount = new Decimal(product.price).minus(new Decimal(targetProductTotal)).toNumber();
777
883
  var isGoodPass = discountType === 'good_pass';
778
- var amount = new Decimal(product.price).minus(new Decimal(targetProductTotal)).toNumber();
779
884
  var discountDetail = {
780
- amount: amount,
781
- type: _selectedDiscount.tag === 'product_discount_card' ? 'discount_card' : discountType,
885
+ amount: actualDiscountAmount,
886
+ type: discountType,
782
887
  discount: {
783
888
  discount_card_type: _selectedDiscount === null || _selectedDiscount === void 0 || (_selectedDiscount$met = _selectedDiscount.metadata) === null || _selectedDiscount$met === void 0 ? void 0 : _selectedDiscount$met.discount_card_type,
784
- fixed_amount: amount,
889
+ fixed_amount: actualDiscountAmount,
785
890
  resource_id: _selectedDiscount.id,
786
891
  title: _selectedDiscount.format_title,
787
892
  original_amount: product.price,
788
893
  product_id: originProduct.id,
789
- percent: _selectedDiscount.par_value
894
+ percent: _selectedDiscount.par_value,
895
+ discount_product_id: _selectedDiscount.product_id
790
896
  },
791
897
  // 前端使用的num数量,为了计算优惠金额
792
898
  _num: isGoodPass ? 1 : product.num,
899
+ config: _selectedDiscount === null || _selectedDiscount === void 0 ? void 0 : _selectedDiscount.config,
793
900
  metadata: {
794
901
  num: 1
795
902
  }
@@ -808,7 +915,6 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
808
915
  // 记录应用了优惠券的商品
809
916
  // 后续更新价格改为 getProductTotalPrice getProductOriginTotalPrice逻辑
810
917
  if (product.isClient) {
811
- debugger;
812
918
  arr.push(_this3.hooks.setProduct(originProduct, {
813
919
  discount_list: [discountDetail],
814
920
  price: _selectedDiscount.tag === 'good_pass' ? 0 : product.price,
@@ -849,25 +955,36 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
849
955
  for (var _i = 0; _i < discountNum; _i++) {
850
956
  var _selectedDiscount2 = applicableDiscounts[_i];
851
957
  usedDiscounts.set(_selectedDiscount2.id, true);
958
+ // 🔥 更新 product_id 使用计数
959
+ if ((_selectedDiscount2.tag || _selectedDiscount2.type) === 'good_pass') {
960
+ var _currentCount = usedProductIdCounts.get(_selectedDiscount2.product_id) || 0;
961
+ usedProductIdCounts.set(_selectedDiscount2.product_id, _currentCount + 1);
962
+ }
852
963
 
853
964
  // 🔥 生成唯一的 _id
854
965
  var uniqueId = "".concat(flatItem._id, "_split_").concat(_i);
966
+
967
+ // 计算折扣后的价格(使用 getDiscountAmount,内部已处理 maxDeductionAmount)
968
+ var discountedPrice = getDiscountAmount(_selectedDiscount2, product.origin_total, product.origin_total);
969
+ var bundleDiscountAmount = new Decimal(product.origin_total || 0).minus(discountedPrice).toNumber();
855
970
  var _discountDetail = {
856
- amount: product.origin_total,
971
+ amount: bundleDiscountAmount,
857
972
  type: 'good_pass',
858
973
  discount: {
859
974
  fixed_amount: product.origin_total,
860
975
  resource_id: _selectedDiscount2.id,
861
976
  title: _selectedDiscount2.format_title,
862
977
  original_amount: product.origin_total,
863
- product_id: product.id
978
+ product_id: product.id,
979
+ discount_product_id: _selectedDiscount2.product_id
864
980
  },
865
981
  metadata: {
866
982
  // 🔥 使用拆分后的唯一 _id
867
983
  custom_product_bundle_map_id: uniqueId,
868
984
  num: 1
869
985
  },
870
- _num: 1
986
+ _num: 1,
987
+ config: _selectedDiscount2 === null || _selectedDiscount2 === void 0 ? void 0 : _selectedDiscount2.config
871
988
  };
872
989
 
873
990
  // 记录实际应用的折扣
@@ -879,9 +996,9 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
879
996
  _id: uniqueId,
880
997
  num: 1,
881
998
  quantity: 1,
882
- price: 0,
883
- // 商品券价格为0
884
- total: 0,
999
+ price: discountedPrice,
1000
+ // 折扣后的价格
1001
+ total: discountedPrice,
885
1002
  discount_list: [_discountDetail],
886
1003
  processed: true,
887
1004
  _discountId: _selectedDiscount2.id
@@ -904,28 +1021,38 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
904
1021
  // 折扣卡:不拆分数量,直接应用
905
1022
  var _selectedDiscount3 = selectedDiscountCard || applicableDiscounts[0];
906
1023
  usedDiscounts.set(_selectedDiscount3.id, true);
1024
+ // 🔥 更新 product_id 使用计数(虽然此处主要是折扣卡,但保持一致性)
1025
+ if ((_selectedDiscount3.tag || _selectedDiscount3.type) === 'good_pass') {
1026
+ var _currentCount2 = usedProductIdCounts.get(_selectedDiscount3.product_id) || 0;
1027
+ usedProductIdCounts.set(_selectedDiscount3.product_id, _currentCount2 + 1);
1028
+ }
907
1029
  var _productOriginTotal = product.original_price || product.price || 0;
908
1030
  var _targetProductTotal = getDiscountAmount(_selectedDiscount3, _productOriginTotal, _productOriginTotal);
909
1031
 
1032
+ // 计算实际折扣金额
1033
+ var bundleActualDiscountAmount = new Decimal(_productOriginTotal).minus(_targetProductTotal).toNumber();
1034
+
910
1035
  // 🔥 使用当前的 _id 作为唯一标识
911
1036
  var _uniqueId = flatItem._id;
912
1037
  var _discountDetail2 = {
913
- amount: new Decimal(_productOriginTotal).minus(_targetProductTotal).toNumber() * (product.num || 1),
1038
+ amount: bundleActualDiscountAmount * (product.num || 1),
914
1039
  type: _selectedDiscount3.tag === 'product_discount_card' ? 'discount_card' : _selectedDiscount3.tag,
915
1040
  discount: {
916
1041
  discount_card_type: _selectedDiscount3 === null || _selectedDiscount3 === void 0 || (_selectedDiscount3$me = _selectedDiscount3.metadata) === null || _selectedDiscount3$me === void 0 ? void 0 : _selectedDiscount3$me.discount_card_type,
917
- fixed_amount: new Decimal(_productOriginTotal).minus(_targetProductTotal).toNumber(),
1042
+ fixed_amount: bundleActualDiscountAmount,
918
1043
  resource_id: _selectedDiscount3.id,
919
1044
  title: _selectedDiscount3.format_title,
920
1045
  original_amount: product.original_price,
921
1046
  product_id: product.id,
922
- percent: _selectedDiscount3.par_value
1047
+ percent: _selectedDiscount3.par_value,
1048
+ discount_product_id: _selectedDiscount3.product_id
923
1049
  },
924
1050
  metadata: {
925
1051
  // 🔥 使用唯一的 _id
926
1052
  custom_product_bundle_map_id: _uniqueId,
927
1053
  num: product.num || 1
928
1054
  },
1055
+ config: _selectedDiscount3 === null || _selectedDiscount3 === void 0 ? void 0 : _selectedDiscount3.config,
929
1056
  _num: (product.num || 1) * ((flatItem === null || flatItem === void 0 || (_flatItem$parentProdu3 = flatItem.parentProduct) === null || _flatItem$parentProdu3 === void 0 ? void 0 : _flatItem$parentProdu3.num) || 1)
930
1057
  };
931
1058
 
@@ -991,7 +1118,6 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
991
1118
 
992
1119
  // 检查是否有bundle子商品需要重组
993
1120
  var hasBundle = product.bundle && Array.isArray(product.bundle) && product.bundle.length > 0;
994
- debugger;
995
1121
  if (!hasBundle) {
996
1122
  // 没有bundle,直接使用主商品处理结果
997
1123
  result.push.apply(result, _toConsumableArray(mainProductArr));
@@ -25,6 +25,7 @@ export interface RulesModuleAPI {
25
25
  holders: {
26
26
  form_record_id: number;
27
27
  }[];
28
+ orderTotalAmount: number;
28
29
  isFormSubject: boolean;
29
30
  }) => DiscountResult;
30
31
  }
@@ -5,6 +5,8 @@ export interface ISummaryState {
5
5
  subtotal: string | number;
6
6
  /** 最终总价 */
7
7
  total: string | number;
8
+ /** 最终原始价格 不包含折扣卡商品券折扣 */
9
+ originTotal: string | number;
8
10
  /** 税率标题 */
9
11
  taxTitle?: string;
10
12
  /** 商品总费率 */
@@ -8,6 +8,12 @@ export declare const calculatePriceDetails: (shopInfo: any, items: CartItem[]) =
8
8
  * @returns 商品总价字符串,保留2位小数
9
9
  */
10
10
  export declare const calculateSubtotal: (items: CartItem[]) => string;
11
+ /**
12
+ * 计算商品小计(不含其他费用 不包含折扣卡商品券抵扣金额)
13
+ * @param items - 购物车商品数组
14
+ * @returns 商品总价字符串,保留2位小数
15
+ */
16
+ export declare const calculateOriginSubtotal: (items: CartItem[]) => string;
11
17
  /**
12
18
  * @title: 单个商品的税费
13
19
  * @description:
@@ -1,16 +1,21 @@
1
1
  import Decimal from 'decimal.js';
2
2
  export var calculatePriceDetails = function calculatePriceDetails(shopInfo, items) {
3
3
  var subtotal = new Decimal(calculateSubtotal(items));
4
+ var subOriginTotal = new Decimal(calculateOriginSubtotal(items));
4
5
  var totalTaxFee = new Decimal(calculateTaxFee(shopInfo, items));
5
6
 
6
7
  // 计算总价
7
8
  var total = shopInfo !== null && shopInfo !== void 0 && shopInfo.is_price_include_tax ? subtotal : subtotal.plus(totalTaxFee);
8
9
 
10
+ // 计算总价 不包含折扣卡商品券折扣信息价格
11
+ var originTotal = shopInfo !== null && shopInfo !== void 0 && shopInfo.is_price_include_tax ? subOriginTotal : subOriginTotal.plus(totalTaxFee);
12
+
9
13
  // 计算定金
10
14
  var deposit = calculateDeposit(items);
11
15
  return {
12
16
  subtotal: subtotal.toFixed(2),
13
17
  total: total.toFixed(2),
18
+ originTotal: originTotal.toFixed(2),
14
19
  taxTitle: shopInfo === null || shopInfo === void 0 ? void 0 : shopInfo.tax_title,
15
20
  totalTaxFee: totalTaxFee.toFixed(2),
16
21
  isPriceIncludeTax: shopInfo === null || shopInfo === void 0 ? void 0 : shopInfo.is_price_include_tax,
@@ -34,6 +39,22 @@ export var calculateSubtotal = function calculateSubtotal(items) {
34
39
  return subtotal.toFixed(2);
35
40
  };
36
41
 
42
+ /**
43
+ * 计算商品小计(不含其他费用 不包含折扣卡商品券抵扣金额)
44
+ * @param items - 购物车商品数组
45
+ * @returns 商品总价字符串,保留2位小数
46
+ */
47
+ export var calculateOriginSubtotal = function calculateOriginSubtotal(items) {
48
+ if (!(items !== null && items !== void 0 && items.length)) {
49
+ return '0.00';
50
+ }
51
+ var subtotal = items.reduce(function (sum, item) {
52
+ var cartItemTotalPrice = new Decimal(item.summaryOriginTotal || 0);
53
+ return sum.plus(cartItemTotalPrice);
54
+ }, new Decimal(0));
55
+ return subtotal.toFixed(2);
56
+ };
57
+
37
58
  /**
38
59
  * @title: 单个商品的税费
39
60
  * @description:
@@ -1,3 +1,4 @@
1
+ import { WalletPassEvaluator } from '../model';
1
2
  import { Plugin } from '../types';
2
3
  /**
3
4
  * WindowPlugin 接口定义
@@ -14,6 +15,7 @@ export interface WindowPlugin extends Plugin {
14
15
  document: Partial<Document>;
15
16
  history: History;
16
17
  interaction?: any;
18
+ getWalletPassEvaluator?: () => WalletPassEvaluator;
17
19
  }
18
20
  /**
19
21
  * 简单的 Storage 接口实现
@@ -144,6 +144,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
144
144
  getSummary(): Promise<{
145
145
  subtotal: string | number;
146
146
  total: string | number;
147
+ originTotal: string | number;
147
148
  taxTitle?: string | undefined;
148
149
  totalTaxFee?: string | number | undefined;
149
150
  isPriceIncludeTax?: 0 | 1 | undefined;
@@ -342,7 +343,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
342
343
  };
343
344
  setOtherData(key: string, value: any): void;
344
345
  getOtherData(key: string): any;
345
- getProductTypeById(id: number): Promise<"duration" | "session" | "normal">;
346
+ getProductTypeById(id: number): Promise<"normal" | "duration" | "session">;
346
347
  /**
347
348
  * 提供给 UI 的方法,减轻 UI 层的计算压力,UI 层只需要传递 cartItemId 和 resourceCode 即返回对应的 renderList
348
349
  *
@@ -403,6 +403,7 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
403
403
  product_id: item.product_id,
404
404
  product_variant_id: item.product_variant_id,
405
405
  quantity: item.num,
406
+ is_price_include_tax: item.is_price_include_tax,
406
407
  // 商品是否含税:1;0
407
408
  is_charge_tax: (_item$is_charge_tax = item.is_charge_tax) !== null && _item$is_charge_tax !== void 0 ? _item$is_charge_tax : 0,
408
409
  // 若商品不含税,计算得到的税费,单位(元)
@@ -427,6 +428,7 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
427
428
  },
428
429
  product_bundle: item.product_bundle.map(function (bundle) {
429
430
  return {
431
+ is_price_include_tax: item.is_price_include_tax,
430
432
  bundle_id: bundle.bundle_id,
431
433
  bundle_product_id: bundle.bundle_product_id,
432
434
  bundle_variant_id: bundle.bundle_variant_id,
@@ -21,6 +21,7 @@ export declare class ShopDiscountImpl extends BaseModule implements Module {
21
21
  getCurrentBookingTime(): string | null;
22
22
  private filterDiscountListByBookingTime;
23
23
  setCustomer(customer: Customer): Promise<void>;
24
+ setOriginTotalAmount(amount: number): void;
24
25
  setHolders(holders: {
25
26
  form_record_id: number;
26
27
  }[]): void;
@@ -55,6 +55,7 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
55
55
  originalDiscountList: [],
56
56
  currentBookingTime: "",
57
57
  filteredDiscountList: [],
58
+ orderTotalAmount: 0,
58
59
  bookingSubject: undefined
59
60
  };
60
61
  return _this;
@@ -287,7 +288,14 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
287
288
  return _setCustomer.apply(this, arguments);
288
289
  }
289
290
  return setCustomer;
290
- }() // 设置holders
291
+ }()
292
+ }, {
293
+ key: "setOriginTotalAmount",
294
+ value: function setOriginTotalAmount(amount) {
295
+ this.store.orderTotalAmount = amount;
296
+ }
297
+
298
+ // 设置holders
291
299
  }, {
292
300
  key: "setHolders",
293
301
  value: function setHolders(holders) {
@@ -316,6 +324,7 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
316
324
  productList: productList,
317
325
  discountList: this.getDiscountList(),
318
326
  holders: this.store.holders || [],
327
+ orderTotalAmount: this.store.orderTotalAmount || 0,
319
328
  isFormSubject: ((_this$store$bookingSu = this.store.bookingSubject) === null || _this$store$bookingSu === void 0 ? void 0 : _this$store$bookingSu.type) === 'form'
320
329
  }, options) || {
321
330
  productList: productList,
@@ -456,6 +465,7 @@ export var ShopDiscountImpl = /*#__PURE__*/function (_BaseModule) {
456
465
  oldDiscountList: this.getDiscountList(),
457
466
  newDiscountList: withScanList,
458
467
  holders: this.store.holders || [],
468
+ orderTotalAmount: this.store.orderTotalAmount || 0,
459
469
  isFormSubject: ((_this$store$bookingSu2 = this.store.bookingSubject) === null || _this$store$bookingSu2 === void 0 ? void 0 : _this$store$bookingSu2.type) === 'form'
460
470
  }) || {
461
471
  isAvailable: false,
@@ -31,6 +31,7 @@ export interface ShopDiscountState {
31
31
  originalDiscountList: Discount[];
32
32
  currentBookingTime: string | null;
33
33
  filteredDiscountList: Discount[];
34
+ orderTotalAmount?: number;
34
35
  bookingSubject?: {
35
36
  type?: 'form' | 'customer';
36
37
  [key: string]: any;
@@ -34,22 +34,37 @@ export var isAllNormalProduct = function isAllNormalProduct(items) {
34
34
  * @returns
35
35
  */
36
36
  export var getDiscountAmount = function getDiscountAmount(discount, total, price) {
37
- var _discount$metadata;
37
+ var discountedPrice = 0;
38
+
38
39
  // 商品券
39
40
  if (discount.tag === 'good_pass') {
40
- return new Decimal(price).minus(new Decimal(price || 0)).toNumber();
41
+ discountedPrice = new Decimal(price).minus(new Decimal(price || 0)).toNumber();
42
+ } else {
43
+ var _discount$metadata;
44
+ // 判断是否是固定金额
45
+ var isFixedAmount = (discount === null || discount === void 0 || (_discount$metadata = discount.metadata) === null || _discount$metadata === void 0 ? void 0 : _discount$metadata.discount_card_type) === 'fixed_amount';
46
+
47
+ // 固定金额 小于0时返回0
48
+ if (isFixedAmount) {
49
+ discountedPrice = Math.max(new Decimal(price).minus(new Decimal(discount.par_value || 0)).toNumber(), 0);
50
+ } else {
51
+ // 百分比:根据折扣卡金额计算
52
+ discountedPrice = new Decimal(100).minus(discount.par_value || 0).div(100).mul(new Decimal(price)).toNumber();
53
+ }
41
54
  }
42
55
 
43
- // 判断是否是固定金额
44
- var isFixedAmount = (discount === null || discount === void 0 || (_discount$metadata = discount.metadata) === null || _discount$metadata === void 0 ? void 0 : _discount$metadata.discount_card_type) === 'fixed_amount';
45
-
46
- // 固定金额 小于0时返回0
47
- if (isFixedAmount) {
48
- return Math.max(new Decimal(price).minus(new Decimal(discount.par_value || 0)).toNumber(), 0);
49
- }
56
+ /*
57
+ // 🔥 如果有 maxDeductionAmount 限制,确保折扣金额不超过限制
58
+ if (discount.config?.maxDeductionAmount) {
59
+ const actualDiscountAmount = new Decimal(price).minus(discountedPrice).toNumber();
60
+ if (actualDiscountAmount > discount.config.maxDeductionAmount) {
61
+ // 折扣金额超过限制,重新计算折扣后价格
62
+ discountedPrice = new Decimal(price).minus(discount.config.maxDeductionAmount).toNumber();
63
+ }
64
+ }
65
+ */
50
66
 
51
- // 百分比:根据折扣卡金额计算
52
- return new Decimal(100).minus(discount.par_value || 0).div(100).mul(new Decimal(price)).toNumber();
67
+ return discountedPrice;
53
68
  };
54
69
  export var getDiscountListAmountTotal = function getDiscountListAmountTotal(discount) {
55
70
  return discount.reduce(function (acc, cur) {
package/lib/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export * from './types';
6
6
  export * from './modules';
7
7
  export * from './plugins';
8
8
  export * from './solution';
9
+ export * from './model';
9
10
  export { PisellOSCore } from './core';
10
11
  import PisellOSCore from './core';
11
12
  export default PisellOSCore;
package/lib/index.js CHANGED
@@ -38,6 +38,7 @@ __reExport(src_exports, require("./types"), module.exports);
38
38
  __reExport(src_exports, require("./modules"), module.exports);
39
39
  __reExport(src_exports, require("./plugins"), module.exports);
40
40
  __reExport(src_exports, require("./solution"), module.exports);
41
+ __reExport(src_exports, require("./model"), module.exports);
41
42
  var import_core = require("./core");
42
43
  var import_core2 = __toESM(require("./core"));
43
44
  var src_default = import_core2.default;
@@ -47,5 +48,6 @@ var src_default = import_core2.default;
47
48
  ...require("./types"),
48
49
  ...require("./modules"),
49
50
  ...require("./plugins"),
50
- ...require("./solution")
51
+ ...require("./solution"),
52
+ ...require("./model")
51
53
  });