@pisell/pisellos 2.2.260 → 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 (129) hide show
  1. package/dist/model/strategy/adapter/index.d.ts +0 -4
  2. package/dist/model/strategy/adapter/index.js +1 -5
  3. package/dist/model/strategy/adapter/promotion/adapter.d.ts +4 -0
  4. package/dist/model/strategy/adapter/promotion/adapter.js +23 -0
  5. package/dist/model/strategy/adapter/promotion/evaluator.d.ts +17 -0
  6. package/dist/model/strategy/adapter/promotion/evaluator.js +279 -6
  7. package/dist/model/strategy/adapter/promotion/examples.d.ts +86 -0
  8. package/dist/model/strategy/adapter/promotion/examples.js +99 -0
  9. package/dist/model/strategy/adapter/promotion/index.d.ts +1 -1
  10. package/dist/model/strategy/adapter/promotion/index.js +1 -1
  11. package/dist/model/strategy/adapter/promotion/type.d.ts +90 -2
  12. package/dist/model/strategy/adapter/promotion/type.js +45 -0
  13. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +17 -13
  14. package/dist/modules/Order/index.d.ts +33 -2
  15. package/dist/modules/Order/index.js +615 -288
  16. package/dist/modules/Order/types.d.ts +20 -2
  17. package/dist/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
  18. package/dist/modules/Order/utils/bundleDiscountHydration.js +144 -0
  19. package/dist/modules/Order/utils.d.ts +4 -0
  20. package/dist/modules/Order/utils.js +116 -29
  21. package/dist/modules/Product/types.d.ts +0 -22
  22. package/dist/modules/ProductList/index.d.ts +1 -1
  23. package/dist/modules/ProductList/index.js +2 -4
  24. package/dist/modules/ProductList/types.d.ts +0 -2
  25. package/dist/modules/Rules/index.d.ts +4 -3
  26. package/dist/modules/Rules/index.js +42 -17
  27. package/dist/modules/Rules/types.d.ts +2 -1
  28. package/dist/modules/SalesSummary/index.d.ts +7 -3
  29. package/dist/modules/SalesSummary/index.js +67 -39
  30. package/dist/modules/SalesSummary/types.d.ts +1 -0
  31. package/dist/modules/SalesSummary/utils.js +2 -1
  32. package/dist/modules/SurchargeList/index.d.ts +6 -4
  33. package/dist/modules/SurchargeList/index.js +62 -39
  34. package/dist/modules/SurchargeList/types.d.ts +6 -2
  35. package/dist/server/index.d.ts +3 -50
  36. package/dist/server/index.js +1075 -1040
  37. package/dist/server/modules/order/index.d.ts +22 -3
  38. package/dist/server/modules/order/index.js +398 -316
  39. package/dist/server/modules/products/index.d.ts +7 -26
  40. package/dist/server/modules/products/index.js +76 -166
  41. package/dist/server/modules/products/types.d.ts +0 -14
  42. package/dist/solution/BaseSales/index.d.ts +22 -2
  43. package/dist/solution/BaseSales/index.js +995 -701
  44. package/dist/solution/BaseSales/types.d.ts +1 -0
  45. package/dist/solution/BaseSales/types.js +2 -1
  46. package/dist/solution/BaseSales/utils/cartPromotion.d.ts +3 -1
  47. package/dist/solution/BaseSales/utils/cartPromotion.js +74 -29
  48. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +6 -3
  49. package/dist/solution/BookingByStep/index.d.ts +1 -1
  50. package/dist/solution/BookingTicket/index.d.ts +9 -1
  51. package/dist/solution/BookingTicket/index.js +153 -6
  52. package/dist/solution/BookingTicket/types.d.ts +0 -2
  53. package/dist/solution/ScanOrder/index.js +31 -20
  54. package/dist/solution/VenueBooking/index.js +30 -19
  55. package/lib/model/strategy/adapter/index.d.ts +0 -4
  56. package/lib/model/strategy/adapter/index.js +2 -13
  57. package/lib/model/strategy/adapter/promotion/adapter.d.ts +4 -0
  58. package/lib/model/strategy/adapter/promotion/adapter.js +20 -0
  59. package/lib/model/strategy/adapter/promotion/evaluator.d.ts +17 -0
  60. package/lib/model/strategy/adapter/promotion/evaluator.js +235 -0
  61. package/lib/model/strategy/adapter/promotion/examples.d.ts +86 -0
  62. package/lib/model/strategy/adapter/promotion/examples.js +91 -0
  63. package/lib/model/strategy/adapter/promotion/index.d.ts +1 -1
  64. package/lib/model/strategy/adapter/promotion/index.js +2 -0
  65. package/lib/model/strategy/adapter/promotion/type.d.ts +90 -2
  66. package/lib/model/strategy/adapter/promotion/type.js +2 -0
  67. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +11 -1
  68. package/lib/modules/Order/index.d.ts +33 -2
  69. package/lib/modules/Order/index.js +402 -64
  70. package/lib/modules/Order/types.d.ts +20 -2
  71. package/lib/modules/Order/utils/bundleDiscountHydration.d.ts +5 -0
  72. package/lib/modules/Order/utils/bundleDiscountHydration.js +139 -0
  73. package/lib/modules/Order/utils.d.ts +4 -0
  74. package/lib/modules/Order/utils.js +90 -3
  75. package/lib/modules/Product/types.d.ts +0 -22
  76. package/lib/modules/ProductList/index.d.ts +1 -1
  77. package/lib/modules/ProductList/index.js +2 -4
  78. package/lib/modules/ProductList/types.d.ts +0 -2
  79. package/lib/modules/Rules/index.d.ts +4 -3
  80. package/lib/modules/Rules/index.js +27 -7
  81. package/lib/modules/Rules/types.d.ts +2 -1
  82. package/lib/modules/SalesSummary/index.d.ts +7 -3
  83. package/lib/modules/SalesSummary/index.js +28 -11
  84. package/lib/modules/SalesSummary/types.d.ts +1 -0
  85. package/lib/modules/SalesSummary/utils.js +2 -0
  86. package/lib/modules/SurchargeList/index.d.ts +6 -4
  87. package/lib/modules/SurchargeList/index.js +41 -21
  88. package/lib/modules/SurchargeList/types.d.ts +6 -2
  89. package/lib/server/index.d.ts +3 -50
  90. package/lib/server/index.js +244 -215
  91. package/lib/server/modules/order/index.d.ts +22 -3
  92. package/lib/server/modules/order/index.js +103 -53
  93. package/lib/server/modules/products/index.d.ts +7 -26
  94. package/lib/server/modules/products/index.js +35 -113
  95. package/lib/server/modules/products/types.d.ts +0 -14
  96. package/lib/solution/BaseSales/index.d.ts +22 -2
  97. package/lib/solution/BaseSales/index.js +246 -60
  98. package/lib/solution/BaseSales/types.d.ts +1 -0
  99. package/lib/solution/BaseSales/types.js +2 -1
  100. package/lib/solution/BaseSales/utils/cartPromotion.d.ts +3 -1
  101. package/lib/solution/BaseSales/utils/cartPromotion.js +59 -16
  102. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +6 -6
  103. package/lib/solution/BookingByStep/index.d.ts +1 -1
  104. package/lib/solution/BookingTicket/index.d.ts +9 -1
  105. package/lib/solution/BookingTicket/index.js +101 -0
  106. package/lib/solution/BookingTicket/types.d.ts +0 -2
  107. package/lib/solution/ScanOrder/index.js +8 -0
  108. package/lib/solution/VenueBooking/index.js +8 -0
  109. package/package.json +1 -1
  110. package/dist/model/strategy/adapter/dataVariant/adapter.d.ts +0 -49
  111. package/dist/model/strategy/adapter/dataVariant/adapter.js +0 -152
  112. package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +0 -87
  113. package/dist/model/strategy/adapter/dataVariant/evaluator.js +0 -755
  114. package/dist/model/strategy/adapter/dataVariant/examples.d.ts +0 -39
  115. package/dist/model/strategy/adapter/dataVariant/examples.js +0 -282
  116. package/dist/model/strategy/adapter/dataVariant/index.d.ts +0 -4
  117. package/dist/model/strategy/adapter/dataVariant/index.js +0 -4
  118. package/dist/model/strategy/adapter/dataVariant/type.d.ts +0 -146
  119. package/dist/model/strategy/adapter/dataVariant/type.js +0 -54
  120. package/lib/model/strategy/adapter/dataVariant/adapter.d.ts +0 -49
  121. package/lib/model/strategy/adapter/dataVariant/adapter.js +0 -139
  122. package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +0 -87
  123. package/lib/model/strategy/adapter/dataVariant/evaluator.js +0 -564
  124. package/lib/model/strategy/adapter/dataVariant/examples.d.ts +0 -39
  125. package/lib/model/strategy/adapter/dataVariant/examples.js +0 -295
  126. package/lib/model/strategy/adapter/dataVariant/index.d.ts +0 -4
  127. package/lib/model/strategy/adapter/dataVariant/index.js +0 -38
  128. package/lib/model/strategy/adapter/dataVariant/type.d.ts +0 -146
  129. package/lib/model/strategy/adapter/dataVariant/type.js +0 -31
@@ -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);
@@ -5,7 +5,3 @@ export { PromotionEvaluator } from './promotion/evaluator';
5
5
  export { PromotionAdapter } from './promotion/adapter';
6
6
  export { ItemRuleEvaluator } from './itemRule/evaluator';
7
7
  export { ItemRuleAdapter } from './itemRule/adapter';
8
- export { DataVariantEvaluator } from './dataVariant/evaluator';
9
- export { DataVariantAdapter } from './dataVariant/adapter';
10
- export { runDataVariantDemo } from './dataVariant/examples';
11
- export * from './dataVariant/type';
@@ -30,15 +30,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/model/strategy/adapter/index.ts
31
31
  var adapter_exports = {};
32
32
  __export(adapter_exports, {
33
- DataVariantAdapter: () => import_adapter3.DataVariantAdapter,
34
- DataVariantEvaluator: () => import_evaluator4.DataVariantEvaluator,
35
33
  ItemRuleAdapter: () => import_adapter2.ItemRuleAdapter,
36
34
  ItemRuleEvaluator: () => import_evaluator3.ItemRuleEvaluator,
37
35
  PromotionAdapter: () => import_adapter.PromotionAdapter,
38
36
  PromotionEvaluator: () => import_evaluator2.PromotionEvaluator,
39
37
  WalletPassAdapter: () => import_walletPass.default,
40
- WalletPassEvaluator: () => import_evaluator.WalletPassEvaluator,
41
- runDataVariantDemo: () => import_examples.runDataVariantDemo
38
+ WalletPassEvaluator: () => import_evaluator.WalletPassEvaluator
42
39
  });
43
40
  module.exports = __toCommonJS(adapter_exports);
44
41
  __reExport(adapter_exports, require("./type"), module.exports);
@@ -48,21 +45,13 @@ var import_evaluator2 = require("./promotion/evaluator");
48
45
  var import_adapter = require("./promotion/adapter");
49
46
  var import_evaluator3 = require("./itemRule/evaluator");
50
47
  var import_adapter2 = require("./itemRule/adapter");
51
- var import_evaluator4 = require("./dataVariant/evaluator");
52
- var import_adapter3 = require("./dataVariant/adapter");
53
- var import_examples = require("./dataVariant/examples");
54
- __reExport(adapter_exports, require("./dataVariant/type"), module.exports);
55
48
  // Annotate the CommonJS export names for ESM import in node:
56
49
  0 && (module.exports = {
57
- DataVariantAdapter,
58
- DataVariantEvaluator,
59
50
  ItemRuleAdapter,
60
51
  ItemRuleEvaluator,
61
52
  PromotionAdapter,
62
53
  PromotionEvaluator,
63
54
  WalletPassAdapter,
64
55
  WalletPassEvaluator,
65
- runDataVariantDemo,
66
- ...require("./type"),
67
- ...require("./dataVariant/type")
56
+ ...require("./type")
68
57
  });
@@ -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
  */
@@ -133,6 +133,9 @@ var PromotionEvaluator = class {
133
133
  for (const product of products) {
134
134
  const applicablePromotions = [];
135
135
  for (const config of configs) {
136
+ if (this.shouldSkipStrategyForProduct(product, config)) {
137
+ continue;
138
+ }
136
139
  const matchInfo = this.getProductMatchInfo(product, config);
137
140
  if (!matchInfo.isMatch) {
138
141
  continue;
@@ -296,6 +299,16 @@ var PromotionEvaluator = class {
296
299
  if (result.giftInfo) {
297
300
  gifts.push(result.giftInfo);
298
301
  }
302
+ } else if (actionType === import_type.PROMOTION_ACTION_TYPES.ITEM_REWARD) {
303
+ const result = this.processItemReward(
304
+ group,
305
+ processedQuantityMap,
306
+ products,
307
+ matchedBundleIndexMap
308
+ );
309
+ pricedProducts.push(...result.products);
310
+ totalOriginalAmount = totalOriginalAmount.plus(result.originalAmount);
311
+ totalFinalAmount = totalFinalAmount.plus(result.finalAmount);
299
312
  }
300
313
  }
301
314
  const remainingProducts = this.getRemainingProducts(
@@ -379,6 +392,9 @@ var PromotionEvaluator = class {
379
392
  for (const product of products) {
380
393
  const applicableStrategies = [];
381
394
  for (const config of configs) {
395
+ if (this.shouldSkipStrategyForProduct(product, config)) {
396
+ continue;
397
+ }
382
398
  let contextProduct = product;
383
399
  if (!matchVariant) {
384
400
  const productMatchRule = this.findProductMatchRule(config);
@@ -455,6 +471,9 @@ var PromotionEvaluator = class {
455
471
  } else if (actionType === "X_ITEMS_FOR_Y_PRICE") {
456
472
  const detail = actionDetail;
457
473
  requiredQuantity = detail.x || 0;
474
+ } else if (actionType === "ITEM_REWARD") {
475
+ const detail = actionDetail;
476
+ requiredQuantity = detail.triggerQuantity || 1;
458
477
  }
459
478
  const productMatchRule = this.findProductMatchRule(config);
460
479
  const eligibleProducts = (productMatchRule == null ? void 0 : productMatchRule.value) || [];
@@ -768,6 +787,213 @@ var PromotionEvaluator = class {
768
787
  giftInfo
769
788
  };
770
789
  }
790
+ /**
791
+ * 处理 商品奖励 促销
792
+ *
793
+ * 1. 使用 group.products 统计触发条件商品数量
794
+ * 2. 按 quantityRule 计算最多奖励的目标商品数量
795
+ * 3. 在全购物车商品中筛选 rewardTargets
796
+ * 4. 按消费者最优(可节省金额从高到低)选择目标单位
797
+ * 5. 对目标商品拆分并写入 finalPrice,触发商品本身不改价
798
+ */
799
+ processItemReward(group, processedQuantityMap, allProducts, matchedBundleIndexMap) {
800
+ const {
801
+ strategyId,
802
+ strategyMetadata,
803
+ actionDetail,
804
+ products: triggerProducts
805
+ } = group;
806
+ const detail = actionDetail;
807
+ const triggerQuantity = this.normalizePositiveInteger(detail.triggerQuantity, 1);
808
+ const rewardQuantity = this.normalizePositiveInteger(detail.rewardQuantity, 1);
809
+ const conditionQuantity = this.getAvailablePromotionQuantity(
810
+ triggerProducts,
811
+ processedQuantityMap,
812
+ matchedBundleIndexMap
813
+ );
814
+ if (conditionQuantity < triggerQuantity) {
815
+ return { products: [], originalAmount: 0, finalAmount: 0 };
816
+ }
817
+ const targetProducts = allProducts.filter(
818
+ (product) => this.isProductMatch(product, detail.rewardTargets || [])
819
+ );
820
+ const targetUnitCandidates = this.buildItemRewardTargetUnits(
821
+ targetProducts,
822
+ processedQuantityMap,
823
+ detail
824
+ );
825
+ if (targetUnitCandidates.length === 0) {
826
+ return { products: [], originalAmount: 0, finalAmount: 0 };
827
+ }
828
+ const rewardLimit = this.resolveItemRewardLimit(
829
+ detail,
830
+ conditionQuantity,
831
+ triggerQuantity,
832
+ rewardQuantity,
833
+ targetUnitCandidates.length
834
+ );
835
+ if (rewardLimit <= 0) {
836
+ return { products: [], originalAmount: 0, finalAmount: 0 };
837
+ }
838
+ const selectedUnits = [...targetUnitCandidates].sort((a, b) => {
839
+ const discountDiff = b.discountAmount.minus(a.discountAmount).toNumber();
840
+ if (discountDiff !== 0)
841
+ return discountDiff;
842
+ return b.originalPrice.minus(a.originalPrice).toNumber();
843
+ }).slice(0, rewardLimit);
844
+ const selectedByProductId = /* @__PURE__ */ new Map();
845
+ for (const unit of selectedUnits) {
846
+ const existing = selectedByProductId.get(unit.product.id);
847
+ if (existing) {
848
+ existing.quantity += 1;
849
+ } else {
850
+ selectedByProductId.set(unit.product.id, {
851
+ quantity: 1,
852
+ finalPrice: unit.finalPrice,
853
+ originalPrice: unit.originalPrice
854
+ });
855
+ }
856
+ }
857
+ const result = [];
858
+ let originalAmount = new import_decimal.default(0);
859
+ let finalAmount = new import_decimal.default(0);
860
+ for (const product of targetProducts) {
861
+ const key = this.getProductKey(product);
862
+ const processedQty = processedQuantityMap.get(key) || 0;
863
+ const availableQty = product.quantity - processedQty;
864
+ if (availableQty <= 0)
865
+ continue;
866
+ const selected = selectedByProductId.get(product.id);
867
+ const selectedQty = (selected == null ? void 0 : selected.quantity) || 0;
868
+ const remainingQty = availableQty - selectedQty;
869
+ if (selectedQty <= 0)
870
+ continue;
871
+ if (selectedQty > 0) {
872
+ result.push({
873
+ ...product,
874
+ id: selectedQty === availableQty ? product.id : this.generateRandomId(),
875
+ originalId: product.id,
876
+ quantity: selectedQty,
877
+ finalPrice: this.formatPrice(selected.finalPrice),
878
+ strategyId,
879
+ strategyMetadata,
880
+ inPromotion: true,
881
+ isSplit: selectedQty !== product.quantity
882
+ });
883
+ originalAmount = originalAmount.plus(
884
+ selected.originalPrice.mul(selectedQty)
885
+ );
886
+ finalAmount = finalAmount.plus(selected.finalPrice.mul(selectedQty));
887
+ }
888
+ if (remainingQty > 0) {
889
+ result.push({
890
+ ...product,
891
+ quantity: remainingQty,
892
+ finalPrice: this.formatPrice(product.price),
893
+ strategyId: void 0,
894
+ strategyMetadata: void 0,
895
+ inPromotion: false,
896
+ isSplit: selectedQty > 0
897
+ });
898
+ const remainingAmount = new import_decimal.default(product.price).mul(remainingQty);
899
+ originalAmount = originalAmount.plus(remainingAmount);
900
+ finalAmount = finalAmount.plus(remainingAmount);
901
+ }
902
+ processedQuantityMap.set(key, processedQty + availableQty);
903
+ }
904
+ return {
905
+ products: result,
906
+ originalAmount: originalAmount.toNumber(),
907
+ finalAmount: finalAmount.toNumber()
908
+ };
909
+ }
910
+ normalizePositiveInteger(value, fallback) {
911
+ const n = Math.floor(Number(value));
912
+ return Number.isFinite(n) && n > 0 ? n : fallback;
913
+ }
914
+ getAvailablePromotionQuantity(products, processedQuantityMap, matchedBundleIndexMap) {
915
+ let total = 0;
916
+ for (const product of products) {
917
+ const key = this.getProductKey(product);
918
+ const processedQty = processedQuantityMap.get(key) || 0;
919
+ const availableQty = product.quantity - processedQty;
920
+ if (availableQty <= 0)
921
+ continue;
922
+ const matchedBundleIndex = matchedBundleIndexMap == null ? void 0 : matchedBundleIndexMap.get(product.id);
923
+ if (matchedBundleIndex !== void 0 && product.bundle) {
924
+ const bundleItem = product.bundle[matchedBundleIndex];
925
+ total += availableQty * ((bundleItem == null ? void 0 : bundleItem.quantity) || 1);
926
+ } else {
927
+ total += availableQty;
928
+ }
929
+ }
930
+ return total;
931
+ }
932
+ buildItemRewardTargetUnits(products, processedQuantityMap, detail) {
933
+ const units = [];
934
+ for (const product of products) {
935
+ const key = this.getProductKey(product);
936
+ const processedQty = processedQuantityMap.get(key) || 0;
937
+ const availableQty = product.quantity - processedQty;
938
+ if (availableQty <= 0)
939
+ continue;
940
+ const originalPrice = new import_decimal.default(product.price || 0);
941
+ const finalPrice = this.resolveItemRewardFinalPrice(originalPrice, detail);
942
+ const discountAmount = originalPrice.minus(finalPrice);
943
+ if (discountAmount.lte(0))
944
+ continue;
945
+ for (let i = 0; i < availableQty; i++) {
946
+ units.push({
947
+ product,
948
+ originalPrice,
949
+ finalPrice,
950
+ discountAmount
951
+ });
952
+ }
953
+ }
954
+ return units;
955
+ }
956
+ resolveItemRewardFinalPrice(originalPrice, detail) {
957
+ const rewardValue = new import_decimal.default(Number(detail.rewardValue) || 0);
958
+ let finalPrice;
959
+ switch (detail.rewardMethod) {
960
+ case "percent_off": {
961
+ const percent = import_decimal.default.min(100, import_decimal.default.max(0, rewardValue));
962
+ finalPrice = originalPrice.mul(new import_decimal.default(100).minus(percent)).div(100);
963
+ break;
964
+ }
965
+ case "amount_off":
966
+ finalPrice = originalPrice.minus(import_decimal.default.max(0, rewardValue));
967
+ break;
968
+ case "fixed_price":
969
+ finalPrice = import_decimal.default.max(0, rewardValue);
970
+ break;
971
+ case "free":
972
+ default:
973
+ finalPrice = new import_decimal.default(0);
974
+ break;
975
+ }
976
+ return import_decimal.default.max(0, import_decimal.default.min(originalPrice, finalPrice)).toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP);
977
+ }
978
+ resolveItemRewardLimit(detail, conditionQuantity, triggerQuantity, rewardQuantity, targetUnitCount) {
979
+ let limit = 0;
980
+ switch (detail.quantityRule) {
981
+ case "all_targets":
982
+ limit = targetUnitCount;
983
+ break;
984
+ case "max_per_order":
985
+ limit = this.normalizePositiveInteger(
986
+ detail.maxRewardQuantity ?? detail.rewardQuantity,
987
+ rewardQuantity
988
+ );
989
+ break;
990
+ case "per_condition_quantity":
991
+ default:
992
+ limit = Math.floor(conditionQuantity / triggerQuantity) * rewardQuantity;
993
+ break;
994
+ }
995
+ return Math.min(Math.max(0, limit), targetUnitCount);
996
+ }
771
997
  /**
772
998
  * 获取未参与任何促销的商品
773
999
  */
@@ -839,8 +1065,17 @@ var PromotionEvaluator = class {
839
1065
  * 检查商品是否在策略的适用范围内
840
1066
  */
841
1067
  isProductInStrategy(product, config) {
1068
+ if (this.shouldSkipStrategyForProduct(product, config)) {
1069
+ return false;
1070
+ }
842
1071
  return this.getProductMatchInfo(product, config).isMatch;
843
1072
  }
1073
+ shouldSkipStrategyForProduct(product, config) {
1074
+ return Boolean(product._promotionOnlyForItemReward) && !this.hasActionType(config, import_type.PROMOTION_ACTION_TYPES.ITEM_REWARD);
1075
+ }
1076
+ hasActionType(config, actionType) {
1077
+ return (config.actions || []).some((action) => (action == null ? void 0 : action.type) === actionType);
1078
+ }
844
1079
  /**
845
1080
  * 查找商品匹配规则
846
1081
  */