@pisell/pisellos 2.2.58 → 2.2.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 (49) hide show
  1. package/dist/model/strategy/adapter/index.d.ts +2 -0
  2. package/dist/model/strategy/adapter/index.js +2 -1
  3. package/dist/model/strategy/adapter/promotion/evaluator.d.ts +213 -0
  4. package/dist/model/strategy/adapter/promotion/evaluator.js +1206 -0
  5. package/dist/model/strategy/adapter/promotion/index.d.ts +206 -0
  6. package/dist/model/strategy/adapter/promotion/index.js +0 -0
  7. package/dist/model/strategy/adapter/promotion/type.d.ts +447 -0
  8. package/dist/model/strategy/adapter/promotion/type.js +209 -0
  9. package/dist/model/strategy/adapter/walletPass/evaluator.js +4 -1
  10. package/dist/model/strategy/engine.d.ts +106 -0
  11. package/dist/model/strategy/engine.js +611 -0
  12. package/dist/model/strategy/index.d.ts +2 -93
  13. package/dist/model/strategy/index.js +6 -549
  14. package/dist/modules/BaseModule.d.ts +4 -0
  15. package/dist/modules/BaseModule.js +5 -0
  16. package/dist/modules/Payment/index.js +5 -5
  17. package/dist/modules/Rules/index.d.ts +1 -0
  18. package/dist/modules/Rules/index.js +30 -22
  19. package/dist/modules/Schedule/index.d.ts +2 -2
  20. package/dist/modules/Schedule/index.js +0 -2
  21. package/dist/solution/BookingByStep/index.js +1 -0
  22. package/dist/solution/Checkout/index.js +38 -40
  23. package/lib/model/strategy/adapter/index.d.ts +2 -0
  24. package/lib/model/strategy/adapter/index.js +5 -0
  25. package/lib/model/strategy/adapter/promotion/evaluator.d.ts +213 -0
  26. package/lib/model/strategy/adapter/promotion/evaluator.js +844 -0
  27. package/lib/model/strategy/adapter/promotion/index.d.ts +206 -0
  28. package/lib/model/strategy/adapter/promotion/index.js +0 -0
  29. package/lib/model/strategy/adapter/promotion/type.d.ts +447 -0
  30. package/lib/model/strategy/adapter/promotion/type.js +51 -0
  31. package/lib/model/strategy/adapter/walletPass/evaluator.js +2 -1
  32. package/lib/model/strategy/engine.d.ts +106 -0
  33. package/lib/model/strategy/engine.js +450 -0
  34. package/lib/model/strategy/index.d.ts +2 -93
  35. package/lib/model/strategy/index.js +6 -381
  36. package/lib/modules/BaseModule.d.ts +4 -0
  37. package/lib/modules/BaseModule.js +3 -0
  38. package/lib/modules/Payment/index.js +5 -4
  39. package/lib/modules/Rules/index.d.ts +1 -0
  40. package/lib/modules/Rules/index.js +25 -23
  41. package/lib/modules/Schedule/index.d.ts +2 -2
  42. package/lib/modules/Schedule/index.js +0 -2
  43. package/lib/solution/BookingByStep/index.js +1 -0
  44. package/lib/solution/Checkout/index.js +4 -5
  45. package/package.json +1 -1
  46. package/dist/modules/Schedule/getDateIsInSchedule.d.ts +0 -32
  47. package/dist/modules/Schedule/getDateIsInSchedule.js +0 -747
  48. package/lib/modules/Schedule/getDateIsInSchedule.d.ts +0 -32
  49. package/lib/modules/Schedule/getDateIsInSchedule.js +0 -451
@@ -201,6 +201,13 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
201
201
  productList: hasApplicableDiscount ? result.productList : productList
202
202
  };
203
203
  }
204
+ }, {
205
+ key: "filterDiscountListByType",
206
+ value: function filterDiscountListByType(discountList, type) {
207
+ return (discountList || []).filter(function (item) {
208
+ return item.type === type || item.tag === type;
209
+ });
210
+ }
204
211
  }, {
205
212
  key: "calcDiscount",
206
213
  value: function calcDiscount(_ref2, options) {
@@ -953,6 +960,9 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
953
960
  }) && (!((_product$discount_lis5 = product.discount_list) !== null && _product$discount_lis5 !== void 0 && _product$discount_lis5.length) || ((_product11 = product) === null || _product11 === void 0 || (_product11 = _product11.discount_list) === null || _product11 === void 0 || (_product11$every = _product11.every) === null || _product11$every === void 0 ? void 0 : _product11$every.call(_product11, function (item) {
954
961
  return item.type === 'product';
955
962
  })));
963
+ if (product.inPromotion) {
964
+ isManualDiscount = false;
965
+ }
956
966
  } else {
957
967
  // bundle子商品:判断父主商品是否手动折扣
958
968
  var parentProduct = flatItem.parentProduct;
@@ -1048,25 +1058,27 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1048
1058
  }),
1049
1059
  price: product.price
1050
1060
  }), {}, {
1051
- discount_list: []
1061
+ discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion')
1052
1062
  }))]);
1053
1063
  } else {
1064
+ var _ref7, _product$_promotion$f, _product12;
1054
1065
  processedProductsMap.set(product._id, [_this3.hooks.setProduct(originProduct, _objectSpread(_objectSpread({}, isManualDiscount ? {
1055
1066
  price: product.price,
1056
1067
  main_product_selling_price: product.price
1057
1068
  } : {
1058
1069
  _id: product._id.split('___')[0] + '___' + index,
1059
- total: product.origin_total || product.total,
1070
+ total: product.inPromotion ? (_ref7 = (_product$_promotion$f = (_product12 = product) === null || _product12 === void 0 || (_product12 = _product12._promotion) === null || _product12 === void 0 ? void 0 : _product12.finalPrice) !== null && _product$_promotion$f !== void 0 ? _product$_promotion$f : product.origin_total) !== null && _ref7 !== void 0 ? _ref7 : product.total : product.origin_total || product.total,
1060
1071
  price: product.price,
1061
1072
  main_product_selling_price: product.price
1062
1073
  }), {}, {
1063
- discount_list: []
1074
+ discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion')
1064
1075
  }))]);
1065
1076
  }
1066
1077
  } else {
1078
+ var _flatItem$bundleItem8;
1067
1079
  // bundle子商品:保存到扁平化Map
1068
1080
  processedFlatItemsMap.set(flatItem._id, [_objectSpread(_objectSpread({}, flatItem), {}, {
1069
- discount_list: [],
1081
+ discount_list: _this3.filterDiscountListByType(((_flatItem$bundleItem8 = flatItem.bundleItem) === null || _flatItem$bundleItem8 === void 0 ? void 0 : _flatItem$bundleItem8.discount_list) || [], 'promotion'),
1070
1082
  price: isManualDiscount ? flatItem.bundleItem.price : flatItem.bundleItem.original_price,
1071
1083
  processed: true
1072
1084
  })]);
@@ -1099,14 +1111,14 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1099
1111
  // 主商品:保持原有逻辑
1100
1112
  if (splitCount < totalQuantity && isNeedSplit) {
1101
1113
  arr.push(_this3.hooks.setProduct(originProduct, {
1102
- discount_list: [],
1114
+ discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion'),
1103
1115
  quantity: totalQuantity - splitCount,
1104
1116
  _id: product._id.split('___')[0],
1105
1117
  total: product.origin_total || product.total
1106
1118
  }));
1107
1119
  }
1108
1120
  for (var i = 0; i < splitCount; i++) {
1109
- var _product$discount_lis10, _originProduct, _selectedDiscount$met, _selectedDiscount$met2;
1121
+ var _originProduct, _selectedDiscount$met, _selectedDiscount$met2;
1110
1122
  // 如果用过折扣卡,也就不存在拆分的情况了,这里直接使用上面计算出来的折扣卡
1111
1123
  var _selectedDiscount = selectedDiscountCard || applicableDiscounts[i];
1112
1124
  // 标记优惠券为已使用
@@ -1123,7 +1135,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1123
1135
  // 优先从 origin_total拿,可能会拿不到(比如用户端预约在没有配置 original_price 的情况下)
1124
1136
  var productOriginTotal = product.origin_total || product.total || 0;
1125
1137
  // 如果当前 product 有 discount_list,则先从 origin_total 拿
1126
- if ((_product$discount_lis10 = product.discount_list) !== null && _product$discount_lis10 !== void 0 && _product$discount_lis10.length && product.origin_total) {
1138
+ if (_this3.filterDiscountListByType(product.discount_list, 'promotion').length && product.origin_total) {
1127
1139
  productOriginTotal = product.origin_total;
1128
1140
  }
1129
1141
  // 如果originProduct?._productInit?.original_price为 0,product.origin_total可能为空,此时取 product.total
@@ -1205,7 +1217,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1205
1217
  }));
1206
1218
  } else {
1207
1219
  arr.push(_this3.hooks.setProduct(originProduct, {
1208
- discount_list: [discountDetail],
1220
+ discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion').concat([discountDetail]),
1209
1221
  _id: product._id.split('___')[0] + '___' + _selectedDiscount.id + index,
1210
1222
  price: _selectedDiscount.tag === 'good_pass' ? 0 : product.price,
1211
1223
  quantity: isNeedSplit ? 1 : product.quantity,
@@ -1376,7 +1388,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1376
1388
  var getDefaultProduct = function getDefaultProduct() {
1377
1389
  if (product.isClient) {
1378
1390
  return _this3.hooks.setProduct(originProduct, {
1379
- discount_list: [],
1391
+ discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion'),
1380
1392
  price: product.price,
1381
1393
  origin_total: getProductOriginTotalPrice({
1382
1394
  product: {
@@ -1397,7 +1409,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1397
1409
  });
1398
1410
  } else {
1399
1411
  return _this3.hooks.setProduct(originProduct, {
1400
- discount_list: [],
1412
+ discount_list: _this3.filterDiscountListByType(product.discount_list, 'promotion'),
1401
1413
  total: product.total,
1402
1414
  origin_total: product.origin_total,
1403
1415
  price: product.price
@@ -1567,8 +1579,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1567
1579
  quantity: 1,
1568
1580
  discount_list: updatedMainDiscountList,
1569
1581
  bundle: newBundleWithDiscount,
1570
- total: new Decimal(newTotalWithDiscount).toDecimalPlaces(2, Decimal.ROUND_HALF_UP).toNumber(),
1571
- origin_total: new Decimal(newOriginTotalWithDiscount).toDecimalPlaces(2, Decimal.ROUND_HALF_UP).toNumber()
1582
+ total: newTotalWithDiscount,
1583
+ origin_total: newOriginTotalWithDiscount
1572
1584
  })));
1573
1585
 
1574
1586
  // 第二个:包含原始bundle (qty=原quantity-1)
@@ -1630,8 +1642,6 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1630
1642
  return accumulator.add(currentPrice.mul(currentNum));
1631
1643
  }, new Decimal(newTotalOriginal)).toNumber();
1632
1644
  }
1633
- newTotalOriginal = new Decimal(newTotalOriginal).toDecimalPlaces(2, Decimal.ROUND_HALF_UP).toNumber();
1634
- newOriginTotalOriginal = new Decimal(newOriginTotalOriginal).toDecimalPlaces(2, Decimal.ROUND_HALF_UP).toNumber();
1635
1645
 
1636
1646
  // 添加第二个主商品:qty=原quantity-1,包含原始bundle
1637
1647
  result.push(_this3.hooks.setProduct(mainProduct, _objectSpread(_objectSpread({}, mainProductData), {}, {
@@ -1736,8 +1746,6 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1736
1746
  return accumulator.add(currentPrice.mul(currentNum));
1737
1747
  }, new Decimal(newTotal)).toNumber();
1738
1748
  }
1739
- newTotal = new Decimal(newTotal).toDecimalPlaces(2, Decimal.ROUND_HALF_UP).toNumber();
1740
- newOriginTotal = new Decimal(newOriginTotal).toDecimalPlaces(2, Decimal.ROUND_HALF_UP).toNumber();
1741
1749
 
1742
1750
  // 生成最终的主商品
1743
1751
  result.push(_this3.hooks.setProduct(mainProduct, _objectSpread(_objectSpread({}, mainProductData), {}, {
@@ -1857,10 +1865,10 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1857
1865
  return true; // 单独购买时可用
1858
1866
  }
1859
1867
  if (isBundleItem) {
1860
- var _flatItem$bundleItem8, _flatItem$bundleItem9;
1868
+ var _flatItem$bundleItem9, _flatItem$bundleItem10;
1861
1869
  // 套餐中购买时,判断是否为原价
1862
- var priceType = (_flatItem$bundleItem8 = flatItem.bundleItem) === null || _flatItem$bundleItem8 === void 0 ? void 0 : _flatItem$bundleItem8.price_type;
1863
- var priceTypeExt = (_flatItem$bundleItem9 = flatItem.bundleItem) === null || _flatItem$bundleItem9 === void 0 ? void 0 : _flatItem$bundleItem9.price_type_ext;
1870
+ var priceType = (_flatItem$bundleItem9 = flatItem.bundleItem) === null || _flatItem$bundleItem9 === void 0 ? void 0 : _flatItem$bundleItem9.price_type;
1871
+ var priceTypeExt = (_flatItem$bundleItem10 = flatItem.bundleItem) === null || _flatItem$bundleItem10 === void 0 ? void 0 : _flatItem$bundleItem10.price_type_ext;
1864
1872
  // original_price 对应:
1865
1873
  // 1. price_type: "markup" && price_type_ext: "product_price"
1866
1874
  // markup_price 对应:
@@ -1898,10 +1906,10 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1898
1906
  return false; // 单独购买时不可用
1899
1907
  }
1900
1908
  if (isBundleItem) {
1901
- var _flatItem$bundleItem10, _flatItem$bundleItem11;
1909
+ var _flatItem$bundleItem11, _flatItem$bundleItem12;
1902
1910
  // 套餐中购买时,判断是否为原价
1903
- var _priceType = (_flatItem$bundleItem10 = flatItem.bundleItem) === null || _flatItem$bundleItem10 === void 0 ? void 0 : _flatItem$bundleItem10.price_type;
1904
- var _priceTypeExt = (_flatItem$bundleItem11 = flatItem.bundleItem) === null || _flatItem$bundleItem11 === void 0 ? void 0 : _flatItem$bundleItem11.price_type_ext;
1911
+ var _priceType = (_flatItem$bundleItem11 = flatItem.bundleItem) === null || _flatItem$bundleItem11 === void 0 ? void 0 : _flatItem$bundleItem11.price_type;
1912
+ var _priceTypeExt = (_flatItem$bundleItem12 = flatItem.bundleItem) === null || _flatItem$bundleItem12 === void 0 ? void 0 : _flatItem$bundleItem12.price_type_ext;
1905
1913
 
1906
1914
  // original_price 对应:
1907
1915
  // 1. price_type: "markup" && price_type_ext: "product_price"
@@ -33,7 +33,7 @@ export declare class ScheduleModule extends BaseModule implements Module, Schedu
33
33
  isInScheduleByDate({ date, schedule, }: {
34
34
  date: string;
35
35
  schedule: any;
36
- }): boolean;
36
+ }): boolean | undefined;
37
37
  /**
38
38
  * 传入一个时间, 判断改时间是否在schedule 内
39
39
  * @param param0 { date: string, schedule: any } date: 日期, schedule: schedule
@@ -42,5 +42,5 @@ export declare class ScheduleModule extends BaseModule implements Module, Schedu
42
42
  static isInScheduleByDate({ date, schedule, }: {
43
43
  date: string;
44
44
  schedule: any;
45
- }): boolean;
45
+ }): boolean | undefined;
46
46
  }
@@ -27,7 +27,6 @@ import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
27
27
  import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
28
28
  import { generateMonthDates, disableAllDates, disableDatesBeforeOneDay } from "../Date/utils";
29
29
  import { calcScheduleDateRange } from "./utils";
30
- import { getDateIsInSchedule } from "./getDateIsInSchedule";
31
30
  dayjs.extend(isSameOrBefore);
32
31
  dayjs.extend(isSameOrAfter);
33
32
  export var ScheduleModule = /*#__PURE__*/function (_BaseModule) {
@@ -271,7 +270,6 @@ export var ScheduleModule = /*#__PURE__*/function (_BaseModule) {
271
270
  var _schedule$repeat_rule, _schedule$repeat_rule2;
272
271
  var date = _ref3.date,
273
272
  schedule = _ref3.schedule;
274
- return getDateIsInSchedule(date, [schedule]);
275
273
  if (schedule.start_time && schedule.end_time) {
276
274
  var isBeforeStartTime = dayjs(date).isBefore(dayjs(schedule.start_time));
277
275
  var isAfterEndTime = dayjs(date).isAfter(dayjs(schedule.end_time));
@@ -1161,6 +1161,7 @@ export var BookingByStepImpl = /*#__PURE__*/function (_BaseModule) {
1161
1161
  var productData = _objectSpread(_objectSpread({}, origin), {}, {
1162
1162
  product_variant_id: product_variant_id
1163
1163
  });
1164
+ debugger;
1164
1165
  // 保护,如果进来的是 session 商品,则必须要有 date 和时间片,否则不允许添加
1165
1166
  if (isSessionProduct(productData)) {
1166
1167
  if (!date || !date.startTime || !date.endTime) {
@@ -760,7 +760,6 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
760
760
  return _regeneratorRuntime().wrap(function _callee10$(_context10) {
761
761
  while (1) switch (_context10.prev = _context10.next) {
762
762
  case 0:
763
- this.payment.wallet.clearAllCache();
764
763
  this.logInfo('updateLocalOrderAsync called', {
765
764
  orderId: params.orderId,
766
765
  orderDataType: (_params$orderData6 = params.orderData) === null || _params$orderData6 === void 0 ? void 0 : _params$orderData6.type,
@@ -772,11 +771,11 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
772
771
  // 基础校验
773
772
  validation = validateLocalOrderData(params.orderData);
774
773
  if (validation.valid) {
775
- _context10.next = 5;
774
+ _context10.next = 4;
776
775
  break;
777
776
  }
778
777
  throw createCheckoutError(CheckoutErrorType.ValidationFailed, "\u8BA2\u5355\u6570\u636E\u9A8C\u8BC1\u5931\u8D25: ".concat(validation.errors.join(', ')));
779
- case 5:
778
+ case 4:
780
779
  // 计算金额
781
780
  amountInfo = extractAmountFromCartSummary(params.cartSummary); // 规范化补充字段
782
781
  params.orderData.created_at = formatDateTime(new Date());
@@ -802,19 +801,19 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
802
801
  }
803
802
 
804
803
  // 保留原有支付项:通过 orderId 找到现有订单(按 id 或 order_id 匹配)
805
- _context10.next = 18;
804
+ _context10.next = 17;
806
805
  return this.payment.getOrderListAsync();
807
- case 18:
806
+ case 17:
808
807
  allOrders = _context10.sent;
809
808
  existingOrder = allOrders.find(function (o) {
810
809
  return String(o.id) === String(params.orderId) || String(o.order_id) === String(params.orderId);
811
810
  });
812
811
  if (!existingOrder) {
813
- _context10.next = 72;
812
+ _context10.next = 71;
814
813
  break;
815
814
  }
816
815
  if (!(params.existPayment && params.existPayment.length > 0)) {
817
- _context10.next = 48;
816
+ _context10.next = 47;
818
817
  break;
819
818
  }
820
819
  this.logInfo('检测到云端支付项,将替换本地订单的支付项列表', {
@@ -838,7 +837,7 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
838
837
  });
839
838
  }); // 计算是否需要支付定金
840
839
  _isNeedDeposit = this.checkIsNeedDepositAsync(params.orderData.bookings, params.orderData.relation_products); // 更新订单,替换支付项列表
841
- _context10.next = 29;
840
+ _context10.next = 28;
842
841
  return this.payment.updateOrderAsync(existingOrder.uuid, {
843
842
  total_amount: amountInfo.totalAmount,
844
843
  is_deposit: _isNeedDeposit.hasDeposit ? 1 : 0,
@@ -856,21 +855,21 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
856
855
  amount_breakdown: amountInfo
857
856
  }
858
857
  });
859
- case 29:
860
- _context10.next = 31;
858
+ case 28:
859
+ _context10.next = 30;
861
860
  return this.payment.getPaymentOrderByUuidAsync(existingOrder.uuid);
862
- case 31:
861
+ case 30:
863
862
  _updated = _context10.sent;
864
863
  if (_updated) {
865
- _context10.next = 34;
864
+ _context10.next = 33;
866
865
  break;
867
866
  }
868
867
  throw createCheckoutError(CheckoutErrorType.UnknownError, '订单更新失败');
869
- case 34:
868
+ case 33:
870
869
  this.store.currentOrder = _updated;
871
- _context10.next = 37;
870
+ _context10.next = 36;
872
871
  return this.updateStateAmountToRemaining(false);
873
- case 37:
872
+ case 36:
874
873
  this.logInfo('本地订单更新成功(已替换云端支付项):', {
875
874
  orderId: params.orderId,
876
875
  uuid: _updated.uuid,
@@ -881,12 +880,12 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
881
880
  });
882
881
 
883
882
  // 事件通知
884
- _context10.next = 40;
883
+ _context10.next = 39;
885
884
  return this.core.effects.emit("".concat(this.name, ":onOrderCreated"), {
886
885
  order: _updated,
887
886
  timestamp: Date.now()
888
887
  });
889
- case 40:
888
+ case 39:
890
889
  // 计算已同步的支付金额
891
890
  syncedPayments = _updated.payment.filter(function (p) {
892
891
  return p.isSynced && p.status !== 'voided';
@@ -906,7 +905,7 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
906
905
  order_wait_pay_amount: Number(_depositDiffAmount) > 0 ? Number(_depositDiffAmount) : Number(_remainingExpectAmount)
907
906
  });
908
907
  return _context10.abrupt("return", _updated);
909
- case 48:
908
+ case 47:
910
909
  // 原有逻辑:保留现有支付项
911
910
  totalAmount = new Decimal(amountInfo.totalAmount || '0');
912
911
  activePayments = (existingOrder.payment || []).filter(function (p) {
@@ -919,7 +918,7 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
919
918
  }, new Decimal(0));
920
919
  remaining = Decimal.max(0, totalAmount.minus(paidAmount)).toFixed(2); // 计算是否需要支付定金,如果需要默认切换到定金模式,以及记录定金总金额,并把当前默认待付金额调整为定金总金额
921
920
  _isNeedDeposit2 = this.checkIsNeedDepositAsync(params.orderData.bookings, params.orderData.relation_products); // 更新到支付模块(使用 uuid,不修改 payment 列表)
922
- _context10.next = 55;
921
+ _context10.next = 54;
923
922
  return this.payment.updateOrderAsync(existingOrder.uuid, {
924
923
  total_amount: amountInfo.totalAmount,
925
924
  is_deposit: _isNeedDeposit2.hasDeposit ? 1 : 0,
@@ -936,21 +935,21 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
936
935
  amount_breakdown: amountInfo
937
936
  }
938
937
  });
939
- case 55:
940
- _context10.next = 57;
938
+ case 54:
939
+ _context10.next = 56;
941
940
  return this.payment.getPaymentOrderByUuidAsync(existingOrder.uuid);
942
- case 57:
941
+ case 56:
943
942
  updated = _context10.sent;
944
943
  if (updated) {
945
- _context10.next = 60;
944
+ _context10.next = 59;
946
945
  break;
947
946
  }
948
947
  throw createCheckoutError(CheckoutErrorType.UnknownError, '订单更新失败');
949
- case 60:
948
+ case 59:
950
949
  this.store.currentOrder = updated;
951
- _context10.next = 63;
950
+ _context10.next = 62;
952
951
  return this.updateStateAmountToRemaining(false);
953
- case 63:
952
+ case 62:
954
953
  this.logInfo('本地订单更新成功(保留支付项):', {
955
954
  orderId: params.orderId,
956
955
  uuid: updated.uuid,
@@ -960,12 +959,12 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
960
959
  });
961
960
 
962
961
  // 事件通知(复用创建事件,便于上层监听刷新)
963
- _context10.next = 66;
962
+ _context10.next = 65;
964
963
  return this.core.effects.emit("".concat(this.name, ":onOrderCreated"), {
965
964
  order: updated,
966
965
  timestamp: Date.now()
967
966
  });
968
- case 66:
967
+ case 65:
969
968
  // 需要减去已经同步给后端的支付过的钱
970
969
  syncedAmount = activePayments.reduce(function (sum, p) {
971
970
  var amt = new Decimal(p.amount || '0');
@@ -981,10 +980,10 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
981
980
  order_wait_pay_amount: Number(depositDiffAmount) > 0 ? Number(depositDiffAmount) : Number(remainingExpectAmount)
982
981
  });
983
982
  return _context10.abrupt("return", updated);
984
- case 72:
983
+ case 71:
985
984
  // 计算是否需要支付定金,如果需要默认切换到定金模式,以及记录定金总金额,并把当前默认待付金额调整为定金总金额
986
985
  isNeedDeposit = this.checkIsNeedDepositAsync(params.orderData.bookings, params.orderData.relation_products); // 没找到现有订单时,回退为创建逻辑(用于异常兜底)
987
- _context10.next = 75;
986
+ _context10.next = 74;
988
987
  return this.payment.createPaymentOrderAsync({
989
988
  order_id: String(params.orderId),
990
989
  total_amount: amountInfo.totalAmount,
@@ -1003,7 +1002,7 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
1003
1002
  amount_breakdown: amountInfo
1004
1003
  }
1005
1004
  });
1006
- case 75:
1005
+ case 74:
1007
1006
  created = _context10.sent;
1008
1007
  this.store.currentOrder = created;
1009
1008
 
@@ -1039,7 +1038,7 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
1039
1038
  this.initWalletData();
1040
1039
  }
1041
1040
  return _context10.abrupt("return", created);
1042
- case 79:
1041
+ case 78:
1043
1042
  case "end":
1044
1043
  return _context10.stop();
1045
1044
  }
@@ -3128,14 +3127,13 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
3128
3127
  return payment.status !== 'voided';
3129
3128
  }) // 只计算未撤销的支付项
3130
3129
  .reduce(function (sum, payment) {
3131
- // const amount = new Decimal(payment.amount || '0');
3132
- // 计算有效支付金额:支付金额 + 抹零金额的绝对值
3133
- // 当 rounding_amount 为负数时,表示抹掉的金额,按绝对值计算有效支付
3134
- // 例如:amount=15, rounding_amount=-0.2,有效支付=15.2(抹掉0.2元零头)
3135
- // 例2:amount=15,rounding_amount=0.2,有效支付 14.8
3136
- var paymentAmount = new Decimal(payment.amount || 0);
3137
- var roundingAmount = new Decimal(payment.rounding_amount || 0);
3138
- var effectiveAmount = paymentAmount.minus(roundingAmount);
3130
+ var amount = new Decimal(payment.amount || '0');
3131
+ var roundingAmount = new Decimal(payment.rounding_amount || '0');
3132
+
3133
+ // 使用 Decimal.js 计算实际支付有效金额:
3134
+ // rounding_amount 为负数时,表示抹掉的金额,应该按绝对值加到实际支付中
3135
+ // 例如:amount=15, rounding_amount=-0.2,实际相当于支付了15.2(抹掉了0.2元的零头)
3136
+ var effectiveAmount = amount.add(roundingAmount.isNegative() ? roundingAmount.abs() : 0);
3139
3137
  return sum.add(effectiveAmount);
3140
3138
  }, new Decimal(0));
3141
3139
  return paidAmount.toFixed(2);
@@ -1,3 +1,5 @@
1
1
  export * from './type';
2
2
  export { default as WalletPassAdapter } from './walletPass';
3
3
  export { WalletPassEvaluator } from './walletPass/evaluator';
4
+ import { PromotionEvaluator, PromotionAdapter } from './promotion';
5
+ export { PromotionEvaluator, PromotionAdapter };
@@ -30,6 +30,8 @@ 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
+ PromotionAdapter: () => import_promotion.PromotionAdapter,
34
+ PromotionEvaluator: () => import_promotion.PromotionEvaluator,
33
35
  WalletPassAdapter: () => import_walletPass.default,
34
36
  WalletPassEvaluator: () => import_evaluator.WalletPassEvaluator
35
37
  });
@@ -37,8 +39,11 @@ module.exports = __toCommonJS(adapter_exports);
37
39
  __reExport(adapter_exports, require("./type"), module.exports);
38
40
  var import_walletPass = __toESM(require("./walletPass"));
39
41
  var import_evaluator = require("./walletPass/evaluator");
42
+ var import_promotion = require("./promotion");
40
43
  // Annotate the CommonJS export names for ESM import in node:
41
44
  0 && (module.exports = {
45
+ PromotionAdapter,
46
+ PromotionEvaluator,
42
47
  WalletPassAdapter,
43
48
  WalletPassEvaluator,
44
49
  ...require("./type")
@@ -0,0 +1,213 @@
1
+ import type { StrategyConfig } from '../../type';
2
+ import { type PromotionProduct, type PromotionActionDetail, type PromotionEvaluatorInput, type ProductPromotionResult, type ApplicablePromotion, type CartEvaluationResult, type CartWithPricingResult } from './type';
3
+ /**
4
+ * Promotion 评估器
5
+ *
6
+ * 用于评估商品适用的促销活动
7
+ * 封装了 StrategyEngine 和 PromotionAdapter 的调用逻辑
8
+ */
9
+ export declare class PromotionEvaluator {
10
+ private engine;
11
+ private adapter;
12
+ private strategyConfigs;
13
+ private locale;
14
+ private locales;
15
+ constructor();
16
+ /**
17
+ * 设置策略配置列表
18
+ */
19
+ setStrategyConfigs(strategyConfigs: StrategyConfig[]): void;
20
+ /**
21
+ * 获取策略配置列表
22
+ */
23
+ getStrategyConfigs(): StrategyConfig[];
24
+ /**
25
+ * 添加策略配置
26
+ */
27
+ addStrategyConfig(strategyConfig: StrategyConfig): void;
28
+ /**
29
+ * 设置语言
30
+ */
31
+ setLocale(locale: string): void;
32
+ /**
33
+ * 设置自定义多语言文案
34
+ */
35
+ setLocales(locales: Record<string, Record<string, string>>): void;
36
+ /**
37
+ * 获取多语言文案
38
+ */
39
+ getText(key: string): string;
40
+ /**
41
+ * 获取多语言名称
42
+ */
43
+ getLocalizedName(name: string | Record<string, string>): string;
44
+ /**
45
+ * 评估商品列表
46
+ *
47
+ * 判断每个商品适用哪些促销活动
48
+ * 支持主商品和 bundle 子商品的匹配
49
+ *
50
+ * @param input 评估输入
51
+ * @returns 每个商品的促销评估结果
52
+ */
53
+ evaluateProducts(input: PromotionEvaluatorInput): ProductPromotionResult[];
54
+ /**
55
+ * 评估购物车
56
+ *
57
+ * 返回所有适用的促销及按促销分组的商品
58
+ * 支持 bundle 子商品的数量计算(主商品数量 × 子商品数量)
59
+ *
60
+ * @param input 评估输入
61
+ * @returns 购物车评估结果
62
+ */
63
+ evaluateCart(input: PromotionEvaluatorInput): CartEvaluationResult;
64
+ /**
65
+ * 评估购物车并计算定价
66
+ *
67
+ * 返回处理后的商品数组(包含拆分、finalPrice)和赠品信息
68
+ * - 对于 X_ITEMS_FOR_Y_PRICE:按原价比例均摊价格,优先使用高价商品
69
+ * - 对于 BUY_X_GET_Y_FREE:计算赠品数量和可选赠品列表
70
+ *
71
+ * @param input 评估输入
72
+ * @returns 带定价的购物车评估结果
73
+ */
74
+ evaluateCartWithPricing(input: PromotionEvaluatorInput): CartWithPricingResult;
75
+ /**
76
+ * 获取商品适用的促销列表
77
+ *
78
+ * 简化方法,用于商品卡片展示
79
+ *
80
+ * @param product 商品
81
+ * @param strategyConfigs 策略配置(可选)
82
+ * @returns 适用的促销列表
83
+ */
84
+ getProductPromotions(product: PromotionProduct, strategyConfigs?: StrategyConfig[]): ApplicablePromotion[];
85
+ /**
86
+ * 获取商品的促销标签
87
+ *
88
+ * 用于商品卡片展示
89
+ *
90
+ * @param product 商品
91
+ * @param strategyConfigs 策略配置(可选)
92
+ * @returns 促销标签列表
93
+ */
94
+ getProductPromotionTags(product: PromotionProduct, strategyConfigs?: StrategyConfig[]): Array<{
95
+ text: string;
96
+ type: string;
97
+ strategyId: string;
98
+ }>;
99
+ /**
100
+ * 查找商品适用的策略配置
101
+ *
102
+ * @param product 商品
103
+ * @param strategyConfigs 策略配置列表(可选)
104
+ * @returns 适用的策略配置列表
105
+ */
106
+ findApplicableStrategies(product: PromotionProduct, strategyConfigs?: StrategyConfig[]): StrategyConfig[];
107
+ /**
108
+ * 批量获取商品列表的适用策略信息
109
+ *
110
+ * 用于给商品列表追加策略标签信息
111
+ * 只检查商品 ID 匹配和策略时间范围
112
+ *
113
+ * @param input 评估输入(商品列表)
114
+ * @param matchVariant 是否需要匹配 product_variant_id,默认 true(严格匹配),false 时只匹配 product_id
115
+ * @returns 每个商品的适用策略完整数据
116
+ */
117
+ getProductsApplicableStrategies(input: PromotionEvaluatorInput, matchVariant?: boolean): Array<{
118
+ product: PromotionProduct;
119
+ applicableStrategies: Array<{
120
+ strategyId: string;
121
+ strategyName: string | Record<string, string>;
122
+ strategyMetadata: any;
123
+ actionType: string;
124
+ actionDetail: PromotionActionDetail;
125
+ display?: {
126
+ text: string | Record<string, string>;
127
+ type: string;
128
+ };
129
+ strategyConfig: StrategyConfig;
130
+ /** 满足促销所需的商品数量 */
131
+ requiredQuantity: number;
132
+ /** 可参与此促销的商品列表 */
133
+ eligibleProducts: Array<{
134
+ product_id: number;
135
+ product_variant_id: number;
136
+ }>;
137
+ }>;
138
+ hasApplicableStrategy: boolean;
139
+ }>;
140
+ /**
141
+ * 获取促销所需数量和可参与商品列表
142
+ *
143
+ * @param actionType 促销类型
144
+ * @param actionDetail 促销详情
145
+ * @param config 策略配置
146
+ * @returns { requiredQuantity, eligibleProducts }
147
+ */
148
+ private getPromotionRequirements;
149
+ /**
150
+ * 按优先级排序促销组
151
+ * 优先级从 strategyConfig.actions[0].priority 获取,数值越小优先级越高
152
+ */
153
+ private sortPromotionGroupsByPriority;
154
+ /**
155
+ * 处理 X件Y元 促销
156
+ *
157
+ * 1. 展开商品为单件列表,按价格从高到低排序
158
+ * 2. 计算可凑成的组数
159
+ * 3. 按原价比例均摊价格
160
+ * 4. 拆分商品(部分参与促销、部分原价)
161
+ *
162
+ * 注意:每个商品按 id 独立处理,不会合并不同 id 的商品
163
+ */
164
+ private processXItemsForYPrice;
165
+ /**
166
+ * 处理 买X送Y 促销
167
+ *
168
+ * 计算赠品数量,商品本身价格不变
169
+ * 支持 bundle 子商品的数量计算(主商品数量 × 子商品数量)
170
+ */
171
+ private processBuyXGetYFree;
172
+ /**
173
+ * 获取未参与任何促销的商品
174
+ */
175
+ private getRemainingProducts;
176
+ /**
177
+ * 价格统一保留两位小数
178
+ */
179
+ private formatPrice;
180
+ /**
181
+ * 获取商品唯一标识 key
182
+ * 使用商品的 id 作为唯一标识,不同 id 的商品不会被合并
183
+ */
184
+ private getProductKey;
185
+ /**
186
+ * 生成随机ID
187
+ */
188
+ private generateRandomId;
189
+ /**
190
+ * 商品匹配结果信息
191
+ */
192
+ private getProductMatchInfo;
193
+ /**
194
+ * 检查商品是否在策略的适用范围内
195
+ */
196
+ private isProductInStrategy;
197
+ /**
198
+ * 查找商品匹配规则
199
+ */
200
+ private findProductMatchRule;
201
+ /**
202
+ * 检查商品ID是否匹配配置列表
203
+ */
204
+ private isProductIdMatch;
205
+ /**
206
+ * 检查商品是否匹配配置(兼容旧方法)
207
+ */
208
+ private isProductMatch;
209
+ /**
210
+ * 获取展示配置
211
+ */
212
+ private getDisplayConfig;
213
+ }