@pisell/pisellos 2.2.259 → 2.2.261

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 (43) hide show
  1. package/dist/model/strategy/adapter/promotion/adapter.d.ts +4 -0
  2. package/dist/model/strategy/adapter/promotion/adapter.js +23 -0
  3. package/dist/model/strategy/adapter/promotion/evaluator.d.ts +17 -0
  4. package/dist/model/strategy/adapter/promotion/evaluator.js +279 -6
  5. package/dist/model/strategy/adapter/promotion/examples.d.ts +86 -0
  6. package/dist/model/strategy/adapter/promotion/examples.js +99 -0
  7. package/dist/model/strategy/adapter/promotion/index.d.ts +1 -1
  8. package/dist/model/strategy/adapter/promotion/index.js +1 -1
  9. package/dist/model/strategy/adapter/promotion/type.d.ts +90 -2
  10. package/dist/model/strategy/adapter/promotion/type.js +45 -0
  11. package/dist/modules/Order/index.d.ts +1 -1
  12. package/dist/modules/Order/utils.js +2 -1
  13. package/dist/modules/Product/index.d.ts +1 -1
  14. package/dist/modules/Rules/index.d.ts +1 -0
  15. package/dist/modules/Rules/index.js +34 -14
  16. package/dist/solution/BaseSales/utils/cartPromotion.d.ts +3 -1
  17. package/dist/solution/BaseSales/utils/cartPromotion.js +74 -29
  18. package/dist/solution/BookingByStep/index.d.ts +1 -1
  19. package/dist/solution/BookingTicket/index.d.ts +1 -1
  20. package/dist/solution/ScanOrder/index.js +31 -20
  21. package/dist/solution/VenueBooking/index.js +30 -19
  22. package/lib/model/strategy/adapter/promotion/adapter.d.ts +4 -0
  23. package/lib/model/strategy/adapter/promotion/adapter.js +20 -0
  24. package/lib/model/strategy/adapter/promotion/evaluator.d.ts +17 -0
  25. package/lib/model/strategy/adapter/promotion/evaluator.js +235 -0
  26. package/lib/model/strategy/adapter/promotion/examples.d.ts +86 -0
  27. package/lib/model/strategy/adapter/promotion/examples.js +91 -0
  28. package/lib/model/strategy/adapter/promotion/index.d.ts +1 -1
  29. package/lib/model/strategy/adapter/promotion/index.js +2 -0
  30. package/lib/model/strategy/adapter/promotion/type.d.ts +90 -2
  31. package/lib/model/strategy/adapter/promotion/type.js +2 -0
  32. package/lib/modules/Order/index.d.ts +1 -1
  33. package/lib/modules/Order/utils.js +6 -1
  34. package/lib/modules/Product/index.d.ts +1 -1
  35. package/lib/modules/Rules/index.d.ts +1 -0
  36. package/lib/modules/Rules/index.js +23 -4
  37. package/lib/solution/BaseSales/utils/cartPromotion.d.ts +3 -1
  38. package/lib/solution/BaseSales/utils/cartPromotion.js +59 -16
  39. package/lib/solution/BookingByStep/index.d.ts +1 -1
  40. package/lib/solution/BookingTicket/index.d.ts +1 -1
  41. package/lib/solution/ScanOrder/index.js +8 -0
  42. package/lib/solution/VenueBooking/index.js +8 -0
  43. package/package.json +1 -1
@@ -1,17 +1,17 @@
1
1
  var _excluded = ["_promotionTags"];
2
2
  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; }
3
3
  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; }
4
- 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; }
5
- 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; }
6
- function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
7
- function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
8
- 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); }
9
4
  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); }
10
5
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
11
6
  function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
12
7
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
13
8
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
14
9
  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; } } }; }
10
+ 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; }
11
+ 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; }
12
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
13
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
14
+ 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); }
15
15
  function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
16
16
  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."); }
17
17
  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); }
@@ -116,24 +116,35 @@ export function getOrderProductOriginalPriceForPromotion(product) {
116
116
  }
117
117
  return getOrderProductBasePrice(product);
118
118
  }
119
+ var X_ITEMS_FOR_Y_PRICE = 'X_ITEMS_FOR_Y_PRICE';
120
+ var BUY_X_GET_Y_FREE = 'BUY_X_GET_Y_FREE';
121
+ var ITEM_REWARD = 'ITEM_REWARD';
122
+ function isManagedPromotionDiscountItem(item) {
123
+ var _item$metadata, _item$metadata2;
124
+ if ((item === null || item === void 0 ? void 0 : item.type) === 'promotion') return true;
125
+ return (item === null || item === void 0 ? void 0 : item.type) === 'product' && (item === null || item === void 0 || (_item$metadata = item.metadata) === null || _item$metadata === void 0 ? void 0 : _item$metadata.source) === 'promotion' && (item === null || item === void 0 || (_item$metadata2 = item.metadata) === null || _item$metadata2 === void 0 ? void 0 : _item$metadata2.actionType) === ITEM_REWARD;
126
+ }
119
127
 
120
128
  /**
121
- * 写入/清除促销 discount_list(type=promotion)。
129
+ * 写入/清除促销 discount_list
122
130
  *
123
131
  * applyDiscount → applyProductDiscountPrices 会从 source_product_price 减去 discount_list 合计
124
132
  * 重算 main_product_selling_price;保留券前 source 时必须同步写入促销差额,否则会还原成原价。
125
133
  *
134
+ * ITEM_REWARD 使用 type=product,复用商品级折扣排他规则,避免客户折扣继续叠加到奖励商品行。
135
+ *
126
136
  * @example
127
137
  * updatePromotionDiscountList(line, { title: '2 items for $10', amount: '17.00', original_amount: '22.00', fixed_amount: '17.00' });
128
138
  */
129
- function updatePromotionDiscountList(item, promotionDiscount) {
139
+ function updatePromotionDiscountList(item, promotionDiscount, options) {
130
140
  var discountList = Array.isArray(item.discount_list) ? _toConsumableArray(item.discount_list) : [];
131
141
  discountList = discountList.filter(function (d) {
132
- return (d === null || d === void 0 ? void 0 : d.type) !== 'promotion';
142
+ return !isManagedPromotionDiscountItem(d);
133
143
  });
134
144
  if (promotionDiscount) {
135
- discountList.push({
136
- type: 'promotion',
145
+ var discountType = (options === null || options === void 0 ? void 0 : options.discountType) || 'promotion';
146
+ discountList.push(_objectSpread({
147
+ type: discountType,
137
148
  amount: promotionDiscount.amount,
138
149
  discount: {
139
150
  original_amount: promotionDiscount.original_amount,
@@ -141,7 +152,12 @@ function updatePromotionDiscountList(item, promotionDiscount) {
141
152
  title: promotionDiscount.title,
142
153
  resource_id: ''
143
154
  }
144
- });
155
+ }, discountType === 'product' ? {
156
+ metadata: {
157
+ source: 'promotion',
158
+ actionType: (options === null || options === void 0 ? void 0 : options.actionType) || ITEM_REWARD
159
+ }
160
+ } : {}));
145
161
  }
146
162
  if (discountList.length > 0) {
147
163
  item.discount_list = discountList;
@@ -149,11 +165,19 @@ function updatePromotionDiscountList(item, promotionDiscount) {
149
165
  delete item.discount_list;
150
166
  }
151
167
  }
152
- var X_ITEMS_FOR_Y_PRICE = 'X_ITEMS_FOR_Y_PRICE';
153
- var BUY_X_GET_Y_FREE = 'BUY_X_GET_Y_FREE';
168
+ function evaluatorHasActionType(evaluator, actionType) {
169
+ var _evaluator$getStrateg;
170
+ var configs = evaluator === null || evaluator === void 0 || (_evaluator$getStrateg = evaluator.getStrategyConfigs) === null || _evaluator$getStrateg === void 0 ? void 0 : _evaluator$getStrateg.call(evaluator);
171
+ if (!Array.isArray(configs)) return false;
172
+ return configs.some(function (config) {
173
+ return ((config === null || config === void 0 ? void 0 : config.actions) || []).some(function (action) {
174
+ return (action === null || action === void 0 ? void 0 : action.type) === actionType;
175
+ });
176
+ });
177
+ }
154
178
 
155
179
  /**
156
- * 将促销单价写入 OrderProduct(含 metadata 三字段 + promotion discount_list)。
180
+ * 将促销单价写入 OrderProduct(含 metadata 三字段 + 行内折扣)。
157
181
  *
158
182
  * @example
159
183
  * applyPromoUnitPriceToLine(newItem, { promoUnitPrice: '5.00', originalBasePrice: 1, strategyTitle: '2 for 10' });
@@ -184,6 +208,9 @@ function applyPromoUnitPriceToLine(item, input) {
184
208
  amount: discountAmount,
185
209
  original_amount: catalogSource,
186
210
  fixed_amount: discountAmount
211
+ }, {
212
+ actionType: input.actionType,
213
+ discountType: input.actionType === ITEM_REWARD ? 'product' : 'promotion'
187
214
  });
188
215
  } else {
189
216
  updatePromotionDiscountList(item, null);
@@ -460,10 +487,10 @@ function getProductBundleForEvaluator(product) {
460
487
  * // => 单行 num=4,清除 _promotion 后重新评估
461
488
  */
462
489
  export function buildConsolidateKeyForPromotion(item) {
463
- var _item$booking_uid, _item$metadata, _item$order_detail_id, _item$product_variant3;
490
+ var _item$booking_uid, _item$metadata3, _item$order_detail_id, _item$product_variant3;
464
491
  var fingerprint = buildProductLineFingerprint(getProductSkuOptions(item), item.product_bundle);
465
492
  var noteSignature = getProductLineNoteSignature(item);
466
- var bookingUid = (_item$booking_uid = item === null || item === void 0 ? void 0 : item.booking_uid) !== null && _item$booking_uid !== void 0 ? _item$booking_uid : item === null || item === void 0 || (_item$metadata = item.metadata) === null || _item$metadata === void 0 ? void 0 : _item$metadata.booking_uid;
493
+ var bookingUid = (_item$booking_uid = item === null || item === void 0 ? void 0 : item.booking_uid) !== null && _item$booking_uid !== void 0 ? _item$booking_uid : item === null || item === void 0 || (_item$metadata3 = item.metadata) === null || _item$metadata3 === void 0 ? void 0 : _item$metadata3.booking_uid;
467
494
  var orderDetailId = (_item$order_detail_id = item === null || item === void 0 ? void 0 : item.order_detail_id) !== null && _item$order_detail_id !== void 0 ? _item$order_detail_id : item === null || item === void 0 ? void 0 : item.orderDetailId;
468
495
  if (orderDetailId !== undefined && orderDetailId !== null && orderDetailId !== '') {
469
496
  var _item$product_variant;
@@ -484,12 +511,12 @@ function consolidateMainProductsForPromotion(entries) {
484
511
  _step5;
485
512
  try {
486
513
  for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
487
- var _item$metadata2;
514
+ var _item$metadata4;
488
515
  var _step5$value = _step5.value,
489
516
  item = _step5$value.item,
490
517
  originalListIndex = _step5$value.originalListIndex;
491
518
  var key = buildConsolidateKeyForPromotion(item);
492
- var wasInPromotion = (item === null || item === void 0 || (_item$metadata2 = item.metadata) === null || _item$metadata2 === void 0 || (_item$metadata2 = _item$metadata2._promotion) === null || _item$metadata2 === void 0 ? void 0 : _item$metadata2.inPromotion) === true;
519
+ var wasInPromotion = (item === null || item === void 0 || (_item$metadata4 = item.metadata) === null || _item$metadata4 === void 0 || (_item$metadata4 = _item$metadata4._promotion) === null || _item$metadata4 === void 0 ? void 0 : _item$metadata4.inPromotion) === true;
493
520
  var existing = groups.get(key);
494
521
  if (!existing) {
495
522
  var mergedItem = cloneDeep(item);
@@ -586,6 +613,9 @@ function splitXItemsPromoLinesByGroup(lines, strategyActionMap) {
586
613
  function generateNumericId() {
587
614
  return Math.floor(Math.random() * 1000000000) + Date.now();
588
615
  }
616
+ function isBookingEditProductLine(product) {
617
+ return (product === null || product === void 0 ? void 0 : product.booking_id) !== undefined && (product === null || product === void 0 ? void 0 : product.booking_id) !== null && product.booking_id !== 0 && product.booking_id !== '0';
618
+ }
589
619
 
590
620
  /**
591
621
  * 把 OrderProduct 转成 evaluator 的 PromotionProduct(仅评估期使用)。
@@ -606,6 +636,7 @@ function convertToPromotionProduct(product, index) {
606
636
  price: getOrderProductOriginalPriceForPromotion(product),
607
637
  quantity: Number((_product$num = product === null || product === void 0 ? void 0 : product.num) !== null && _product$num !== void 0 ? _product$num : 1) || 1,
608
638
  bundle: getProductBundleForEvaluator(product),
639
+ _promotionOnlyForItemReward: isBookingEditProductLine(product),
609
640
  _originalItem: originalItem,
610
641
  _originalId: getOrderProductUid(product),
611
642
  _originalIndex: index
@@ -813,6 +844,9 @@ export function resolveStrategyRequiredQuantity(matched) {
813
844
  if (matched.actionType === 'BUY_X_GET_Y_FREE') {
814
845
  return Number(detail.buyQuantity) || 1;
815
846
  }
847
+ if (matched.actionType === 'ITEM_REWARD') {
848
+ return Number(detail.triggerQuantity) || 1;
849
+ }
816
850
  return 1;
817
851
  }
818
852
 
@@ -972,7 +1006,8 @@ export function appendPromotionTags(products, evaluator) {
972
1006
  * 处理购物车的促销计算与赠品差异化。
973
1007
  *
974
1008
  * 流程:
975
- * 1. 分离 main / gift / edit-product 三类(带 `booking_id` 的编辑态商品不参与促销)
1009
+ * 1. 分离 main / gift / edit-product 三类(普通促销下带 `booking_id` 的编辑态商品不参与;
1010
+ * 配置 ITEM_REWARD 时,编辑态商品也参与商品奖励重算)
976
1011
  * 2. 转 PromotionProduct 喂评估器 → 拿到 `evaluateCartWithPricing` 与 `getProductsApplicableStrategies`
977
1012
  * 3. 把 PricedProduct 映射回 OrderProduct 形态:
978
1013
  * - 参与促销的,写 `metadata._promotion` + 调整 `selling_price` / `main_product_selling_price`
@@ -1002,6 +1037,7 @@ export function processCartPromotion(list, evaluator, options) {
1002
1037
  if (!list || list.length === 0 || !evaluator) return empty;
1003
1038
 
1004
1039
  // 0. 分类
1040
+ var shouldIncludeEditProductsForItemReward = evaluatorHasActionType(evaluator, ITEM_REWARD);
1005
1041
  var mainProductsWithIndex = [];
1006
1042
  var existingGiftsWithIndex = [];
1007
1043
  var editProductsWithIndex = [];
@@ -1018,11 +1054,18 @@ export function processCartPromotion(list, evaluator, options) {
1018
1054
  item: item,
1019
1055
  originalListIndex: i
1020
1056
  });
1021
- } else if ((item === null || item === void 0 ? void 0 : item.booking_id) !== undefined && (item === null || item === void 0 ? void 0 : item.booking_id) !== null && item.booking_id !== 0 && item.booking_id !== '0') {
1022
- editProductsWithIndex.push({
1023
- item: item,
1024
- originalListIndex: i
1025
- });
1057
+ } else if (isBookingEditProductLine(item)) {
1058
+ if (shouldIncludeEditProductsForItemReward) {
1059
+ mainProductsWithIndex.push({
1060
+ item: item,
1061
+ originalListIndex: i
1062
+ });
1063
+ } else {
1064
+ editProductsWithIndex.push({
1065
+ item: item,
1066
+ originalListIndex: i
1067
+ });
1068
+ }
1026
1069
  } else {
1027
1070
  mainProductsWithIndex.push({
1028
1071
  item: item,
@@ -1077,16 +1120,17 @@ export function processCartPromotion(list, evaluator, options) {
1077
1120
  var promotionProducts = [];
1078
1121
  var originalItemMap = new Map();
1079
1122
  var productsForStrategies = consolidatedMainProductsWithIndex.map(function (_ref16, i) {
1080
- var _item$product_id, _item$product_variant5, _item$metadata3, _item$num;
1123
+ var _item$product_id, _item$product_variant5, _item$metadata5, _item$num;
1081
1124
  var item = _ref16.item;
1082
1125
  return {
1083
1126
  id: i,
1084
1127
  product_id: Number((_item$product_id = item === null || item === void 0 ? void 0 : item.product_id) !== null && _item$product_id !== void 0 ? _item$product_id : 0) || 0,
1085
1128
  product_variant_id: Number((_item$product_variant5 = item === null || item === void 0 ? void 0 : item.product_variant_id) !== null && _item$product_variant5 !== void 0 ? _item$product_variant5 : 0) || 0,
1086
- name: (item === null || item === void 0 || (_item$metadata3 = item.metadata) === null || _item$metadata3 === void 0 ? void 0 : _item$metadata3.product_name) || (item === null || item === void 0 ? void 0 : item.title) || '',
1129
+ name: (item === null || item === void 0 || (_item$metadata5 = item.metadata) === null || _item$metadata5 === void 0 ? void 0 : _item$metadata5.product_name) || (item === null || item === void 0 ? void 0 : item.title) || '',
1087
1130
  price: getOrderProductBasePrice(item),
1088
1131
  quantity: Number((_item$num = item === null || item === void 0 ? void 0 : item.num) !== null && _item$num !== void 0 ? _item$num : 1) || 1,
1089
- bundle: getProductBundleForEvaluator(item)
1132
+ bundle: getProductBundleForEvaluator(item),
1133
+ _promotionOnlyForItemReward: isBookingEditProductLine(item)
1090
1134
  };
1091
1135
  });
1092
1136
  for (var _i = 0; _i < consolidatedMainProductsWithIndex.length; _i++) {
@@ -1234,12 +1278,13 @@ export function processCartPromotion(list, evaluator, options) {
1234
1278
  var priceUnchangedPromo = _priced.inPromotion && Number(_priced.finalPrice) === Number(originalBasePrice);
1235
1279
  if (shouldModifyPrice) {
1236
1280
  if (_priced.inPromotion && !priceUnchangedPromo) {
1237
- var _priced$strategyMetad;
1281
+ var _priced$strategyMetad, _strategyActionMap$ge;
1238
1282
  var promoUnitPrice = new Decimal(_priced.finalPrice).toDecimalPlaces(2).toFixed(2);
1239
1283
  applyPromoUnitPriceToLine(newItem, {
1240
1284
  promoUnitPrice: promoUnitPrice,
1241
1285
  originalBasePrice: originalBasePrice,
1242
- strategyTitle: (_priced$strategyMetad = _priced.strategyMetadata) === null || _priced$strategyMetad === void 0 ? void 0 : _priced$strategyMetad.name
1286
+ strategyTitle: (_priced$strategyMetad = _priced.strategyMetadata) === null || _priced$strategyMetad === void 0 ? void 0 : _priced$strategyMetad.name,
1287
+ actionType: _priced.strategyId ? (_strategyActionMap$ge = strategyActionMap.get(_priced.strategyId)) === null || _strategyActionMap$ge === void 0 ? void 0 : _strategyActionMap$ge.actionType : undefined
1243
1288
  });
1244
1289
  } else {
1245
1290
  // 撤销上一轮促销:还原 selling_price 到 main_product_original_price 派生值
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
311
311
  date: string;
312
312
  status: string;
313
313
  week: string;
314
- weekNum: 0 | 1 | 2 | 3 | 4 | 5 | 6;
314
+ weekNum: 0 | 2 | 1 | 5 | 3 | 4 | 6;
315
315
  }[]>;
316
316
  submitTimeSlot(timeSlots: TimeSliceItem): void;
317
317
  private getScheduleDataByIds;
@@ -322,7 +322,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
322
322
  * 获取当前的客户搜索条件
323
323
  * @returns 当前搜索条件
324
324
  */
325
- getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
325
+ getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "skip" | "num">;
326
326
  /**
327
327
  * 获取客户列表状态(包含滚动加载相关状态)
328
328
  * @returns 客户状态
@@ -41,6 +41,10 @@ import { composeLinePrice, createUuidV4, getProductSkuOptions, normalizeSubmitCo
41
41
  import dayjs from 'dayjs';
42
42
  import { ItemRuleEvaluator } from "../../model/strategy/adapter/itemRule";
43
43
  export * from "./types";
44
+ function isItemRewardProductDiscount(discount) {
45
+ var _discount$metadata, _discount$metadata2;
46
+ return (discount === null || discount === void 0 ? void 0 : discount.type) === 'product' && (discount === null || discount === void 0 || (_discount$metadata = discount.metadata) === null || _discount$metadata === void 0 ? void 0 : _discount$metadata.source) === 'promotion' && (discount === null || discount === void 0 || (_discount$metadata2 = discount.metadata) === null || _discount$metadata2 === void 0 ? void 0 : _discount$metadata2.actionType) === 'ITEM_REWARD';
47
+ }
44
48
  export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
45
49
  _inherits(ScanOrderImpl, _BaseModule);
46
50
  var _super = _createSuper(ScanOrderImpl);
@@ -1177,7 +1181,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1177
1181
  _iterator3.s();
1178
1182
  case 19:
1179
1183
  if ((_step3 = _iterator3.n()).done) {
1180
- _context15.next = 33;
1184
+ _context15.next = 36;
1181
1185
  break;
1182
1186
  }
1183
1187
  product = _step3.value;
@@ -1185,8 +1189,15 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1185
1189
  _context15.next = 23;
1186
1190
  break;
1187
1191
  }
1188
- return _context15.abrupt("continue", 31);
1192
+ return _context15.abrupt("continue", 34);
1189
1193
  case 23:
1194
+ if (!(product.discount_list || []).some(isItemRewardProductDiscount)) {
1195
+ _context15.next = 26;
1196
+ break;
1197
+ }
1198
+ product.discount_list = (product.discount_list || []).filter(isItemRewardProductDiscount);
1199
+ return _context15.abrupt("continue", 34);
1200
+ case 26:
1190
1201
  product.discount_list = (product.discount_list || []).filter(function (pd) {
1191
1202
  var _pd$discount$resource, _pd$discount;
1192
1203
  var rid = (_pd$discount$resource = (_pd$discount = pd.discount) === null || _pd$discount === void 0 ? void 0 : _pd$discount.resource_id) !== null && _pd$discount$resource !== void 0 ? _pd$discount$resource : pd.id;
@@ -1210,47 +1221,47 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
1210
1221
  mainPrice: newMainSellingPrice,
1211
1222
  bundle: product.product_bundle
1212
1223
  });
1213
- case 31:
1224
+ case 34:
1214
1225
  _context15.next = 19;
1215
1226
  break;
1216
- case 33:
1217
- _context15.next = 38;
1227
+ case 36:
1228
+ _context15.next = 41;
1218
1229
  break;
1219
- case 35:
1220
- _context15.prev = 35;
1221
- _context15.t0 = _context15["catch"](17);
1222
- _iterator3.e(_context15.t0);
1223
1230
  case 38:
1224
1231
  _context15.prev = 38;
1225
- _iterator3.f();
1226
- return _context15.finish(38);
1232
+ _context15.t0 = _context15["catch"](17);
1233
+ _iterator3.e(_context15.t0);
1227
1234
  case 41:
1235
+ _context15.prev = 41;
1236
+ _iterator3.f();
1237
+ return _context15.finish(41);
1238
+ case 44:
1228
1239
  OrderModule.populateSavedAmounts(tempOrder.products, nextDiscountList);
1229
- _context15.next = 44;
1240
+ _context15.next = 47;
1230
1241
  return discountModule === null || discountModule === void 0 ? void 0 : discountModule.setDiscountList(nextDiscountList);
1231
- case 44:
1242
+ case 47:
1232
1243
  tempOrder.discount_list = (nextDiscountList || []).filter(function (d) {
1233
1244
  return d.isSelected;
1234
1245
  });
1235
- _context15.next = 47;
1246
+ _context15.next = 50;
1236
1247
  return this.store.order.recalculateSummary({
1237
1248
  createIfMissing: true
1238
1249
  });
1239
- case 47:
1250
+ case 50:
1240
1251
  this.store.order.persistTempOrder();
1241
1252
  this.logMethodSuccess('setDiscountSelected', params);
1242
- _context15.next = 55;
1253
+ _context15.next = 58;
1243
1254
  break;
1244
- case 51:
1245
- _context15.prev = 51;
1255
+ case 54:
1256
+ _context15.prev = 54;
1246
1257
  _context15.t1 = _context15["catch"](1);
1247
1258
  this.logMethodError('setDiscountSelected', _context15.t1);
1248
1259
  throw _context15.t1;
1249
- case 55:
1260
+ case 58:
1250
1261
  case "end":
1251
1262
  return _context15.stop();
1252
1263
  }
1253
- }, _callee15, this, [[1, 51], [17, 35, 38, 41]]);
1264
+ }, _callee15, this, [[1, 54], [17, 38, 41, 44]]);
1254
1265
  }));
1255
1266
  function setDiscountSelected(_x8) {
1256
1267
  return _setDiscountSelected.apply(this, arguments);
@@ -51,6 +51,10 @@ import { RegisterAndLoginHooks } from "../RegisterAndLogin/types";
51
51
  import Decimal from 'decimal.js';
52
52
  export * from "./types";
53
53
  var OPEN_DATA_SECTION_CODES = ['basic', 'fulfillment', 'reservation', 'sale', 'menu', 'availability', 'workflow', 'checkout'];
54
+ function isItemRewardProductDiscount(discount) {
55
+ var _discount$metadata, _discount$metadata2;
56
+ return (discount === null || discount === void 0 ? void 0 : discount.type) === 'product' && (discount === null || discount === void 0 || (_discount$metadata = discount.metadata) === null || _discount$metadata === void 0 ? void 0 : _discount$metadata.source) === 'promotion' && (discount === null || discount === void 0 || (_discount$metadata2 = discount.metadata) === null || _discount$metadata2 === void 0 ? void 0 : _discount$metadata2.actionType) === 'ITEM_REWARD';
57
+ }
54
58
  function cloneCustomDepositData(customDepositData) {
55
59
  if (!customDepositData || _typeof(customDepositData) !== 'object') return undefined;
56
60
  return _objectSpread(_objectSpread({}, customDepositData), {}, {
@@ -2163,7 +2167,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2163
2167
  _iterator14.s();
2164
2168
  case 21:
2165
2169
  if ((_step14 = _iterator14.n()).done) {
2166
- _context21.next = 35;
2170
+ _context21.next = 38;
2167
2171
  break;
2168
2172
  }
2169
2173
  product = _step14.value;
@@ -2171,8 +2175,15 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2171
2175
  _context21.next = 25;
2172
2176
  break;
2173
2177
  }
2174
- return _context21.abrupt("continue", 33);
2178
+ return _context21.abrupt("continue", 36);
2175
2179
  case 25:
2180
+ if (!(product.discount_list || []).some(isItemRewardProductDiscount)) {
2181
+ _context21.next = 28;
2182
+ break;
2183
+ }
2184
+ product.discount_list = (product.discount_list || []).filter(isItemRewardProductDiscount);
2185
+ return _context21.abrupt("continue", 36);
2186
+ case 28:
2176
2187
  // 1. 把 product.discount_list 和当前选中的 discount 对齐(剔除已取消的券)
2177
2188
  product.discount_list = (product.discount_list || []).filter(function (pd) {
2178
2189
  var _pd$discount$resource, _pd$discount;
@@ -2197,36 +2208,36 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2197
2208
  mainPrice: newMainSellingPrice,
2198
2209
  bundle: product.product_bundle
2199
2210
  });
2200
- case 33:
2211
+ case 36:
2201
2212
  _context21.next = 21;
2202
2213
  break;
2203
- case 35:
2204
- _context21.next = 40;
2214
+ case 38:
2215
+ _context21.next = 43;
2205
2216
  break;
2206
- case 37:
2207
- _context21.prev = 37;
2208
- _context21.t0 = _context21["catch"](19);
2209
- _iterator14.e(_context21.t0);
2210
2217
  case 40:
2211
2218
  _context21.prev = 40;
2212
- _iterator14.f();
2213
- return _context21.finish(40);
2219
+ _context21.t0 = _context21["catch"](19);
2220
+ _iterator14.e(_context21.t0);
2214
2221
  case 43:
2222
+ _context21.prev = 43;
2223
+ _iterator14.f();
2224
+ return _context21.finish(43);
2225
+ case 46:
2215
2226
  OrderModule.populateSavedAmounts(tempOrder.products, nextDiscountList);
2216
- _context21.next = 46;
2227
+ _context21.next = 49;
2217
2228
  return discountModule === null || discountModule === void 0 ? void 0 : discountModule.setDiscountList(nextDiscountList);
2218
- case 46:
2229
+ case 49:
2219
2230
  tempOrder.discount_list = (nextDiscountList || []).filter(function (d) {
2220
2231
  return d.isSelected;
2221
2232
  });
2222
2233
  afterApplyTarget = this.store.order.getDiscountList().find(function (d) {
2223
2234
  return d.id === params.discountId;
2224
2235
  }) || null;
2225
- _context21.next = 50;
2236
+ _context21.next = 53;
2226
2237
  return this.store.order.recalculateSummary({
2227
2238
  createIfMissing: true
2228
2239
  });
2229
- case 50:
2240
+ case 53:
2230
2241
  this.store.order.persistTempOrder();
2231
2242
  finalSummary = ((_this$store$order$get = this.store.order.getTempOrder()) === null || _this$store$order$get === void 0 ? void 0 : _this$store$order$get.summary) || null;
2232
2243
  finalProduct = ((_this$store$order$get2 = this.store.order.getTempOrder()) === null || _this$store$order$get2 === void 0 || (_this$store$order$get2 = _this$store$order$get2.products) === null || _this$store$order$get2 === void 0 ? void 0 : _this$store$order$get2[0]) || null;
@@ -2235,16 +2246,16 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
2235
2246
  return d.id === params.discountId;
2236
2247
  }) || null;
2237
2248
  return _context21.abrupt("return", this.store.order.getDiscountList());
2238
- case 58:
2239
- _context21.prev = 58;
2249
+ case 61:
2250
+ _context21.prev = 61;
2240
2251
  _context21.t1 = _context21["catch"](1);
2241
2252
  this.logMethodError('setDiscountSelected', _context21.t1);
2242
2253
  throw _context21.t1;
2243
- case 62:
2254
+ case 65:
2244
2255
  case "end":
2245
2256
  return _context21.stop();
2246
2257
  }
2247
- }, _callee21, this, [[1, 58], [19, 37, 40, 43]]);
2258
+ }, _callee21, this, [[1, 61], [19, 40, 43, 46]]);
2248
2259
  }));
2249
2260
  function setDiscountSelected(_x15) {
2250
2261
  return _setDiscountSelected.apply(this, arguments);
@@ -48,6 +48,10 @@ export declare class PromotionAdapter implements BusinessAdapter {
48
48
  * 解析 买X送Y Action
49
49
  */
50
50
  private parseBuyXGetYFreeAction;
51
+ /**
52
+ * 解析 商品奖励 Action
53
+ */
54
+ private parseItemRewardAction;
51
55
  /**
52
56
  * 获取适用的商品列表
53
57
  *
@@ -134,6 +134,8 @@ var PromotionAdapter = class {
134
134
  return this.parseXItemsForYPriceAction(action);
135
135
  case import_type.PROMOTION_ACTION_TYPES.BUY_X_GET_Y_FREE:
136
136
  return this.parseBuyXGetYFreeAction(action);
137
+ case import_type.PROMOTION_ACTION_TYPES.ITEM_REWARD:
138
+ return this.parseItemRewardAction(action);
137
139
  default:
138
140
  return void 0;
139
141
  }
@@ -167,6 +169,24 @@ var PromotionAdapter = class {
167
169
  giftProducts: config.giftProducts || []
168
170
  };
169
171
  }
172
+ /**
173
+ * 解析 商品奖励 Action
174
+ */
175
+ parseItemRewardAction(action) {
176
+ const value = action.value || {};
177
+ const config = action.config || {};
178
+ return {
179
+ type: import_type.PROMOTION_ACTION_TYPES.ITEM_REWARD,
180
+ rewardMethod: value.rewardMethod || "free",
181
+ rewardValue: Number(value.rewardValue || 0),
182
+ quantityRule: value.quantityRule || "per_condition_quantity",
183
+ triggerQuantity: Number(value.triggerQuantity || 1),
184
+ rewardQuantity: Number(value.rewardQuantity || 1),
185
+ maxRewardQuantity: value.maxRewardQuantity === void 0 || value.maxRewardQuantity === null ? void 0 : Number(value.maxRewardQuantity),
186
+ rewardTargets: Array.isArray(config.rewardTargets) ? config.rewardTargets : [],
187
+ targetSelection: config.targetSelection || "consumer_best"
188
+ };
189
+ }
170
190
  /**
171
191
  * 获取适用的商品列表
172
192
  *
@@ -169,6 +169,21 @@ export declare class PromotionEvaluator {
169
169
  * 支持 bundle 子商品的数量计算(主商品数量 × 子商品数量)
170
170
  */
171
171
  private processBuyXGetYFree;
172
+ /**
173
+ * 处理 商品奖励 促销
174
+ *
175
+ * 1. 使用 group.products 统计触发条件商品数量
176
+ * 2. 按 quantityRule 计算最多奖励的目标商品数量
177
+ * 3. 在全购物车商品中筛选 rewardTargets
178
+ * 4. 按消费者最优(可节省金额从高到低)选择目标单位
179
+ * 5. 对目标商品拆分并写入 finalPrice,触发商品本身不改价
180
+ */
181
+ private processItemReward;
182
+ private normalizePositiveInteger;
183
+ private getAvailablePromotionQuantity;
184
+ private buildItemRewardTargetUnits;
185
+ private resolveItemRewardFinalPrice;
186
+ private resolveItemRewardLimit;
172
187
  /**
173
188
  * 获取未参与任何促销的商品
174
189
  */
@@ -194,6 +209,8 @@ export declare class PromotionEvaluator {
194
209
  * 检查商品是否在策略的适用范围内
195
210
  */
196
211
  private isProductInStrategy;
212
+ private shouldSkipStrategyForProduct;
213
+ private hasActionType;
197
214
  /**
198
215
  * 查找商品匹配规则
199
216
  */