@pisell/pisellos 0.10.44 → 0.10.45

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 (40) hide show
  1. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  2. package/dist/model/strategy/adapter/walletPass/evaluator.d.ts +2 -0
  3. package/dist/model/strategy/adapter/walletPass/evaluator.js +4 -2
  4. package/dist/modules/Customer/index.js +2 -1
  5. package/dist/modules/Discount/availability.d.ts +7 -0
  6. package/dist/modules/Discount/availability.js +49 -0
  7. package/dist/modules/Discount/index.d.ts +1 -3
  8. package/dist/modules/Discount/index.js +12 -151
  9. package/dist/modules/Discount/types.d.ts +6 -0
  10. package/dist/modules/Order/index.js +155 -130
  11. package/dist/modules/Order/utils.d.ts +1 -1
  12. package/dist/modules/Order/utils.js +84 -59
  13. package/dist/modules/Product/index.d.ts +1 -1
  14. package/dist/modules/Rules/index.js +50 -16
  15. package/dist/solution/BaseSales/types.d.ts +2 -2
  16. package/dist/solution/BookingByStep/index.d.ts +1 -1
  17. package/dist/solution/ShopDiscount/index.d.ts +1 -0
  18. package/dist/solution/ShopDiscount/index.js +59 -22
  19. package/dist/solution/ShopDiscount/utils.d.ts +4 -2
  20. package/dist/solution/ShopDiscount/utils.js +40 -21
  21. package/lib/model/strategy/adapter/walletPass/evaluator.d.ts +2 -0
  22. package/lib/model/strategy/adapter/walletPass/evaluator.js +2 -0
  23. package/lib/modules/Customer/index.js +1 -0
  24. package/lib/modules/Discount/availability.d.ts +7 -0
  25. package/lib/modules/Discount/availability.js +43 -0
  26. package/lib/modules/Discount/index.d.ts +1 -3
  27. package/lib/modules/Discount/index.js +10 -131
  28. package/lib/modules/Discount/types.d.ts +6 -0
  29. package/lib/modules/Order/index.js +22 -8
  30. package/lib/modules/Order/utils.d.ts +1 -1
  31. package/lib/modules/Order/utils.js +20 -2
  32. package/lib/modules/Product/index.d.ts +1 -1
  33. package/lib/modules/Rules/index.js +42 -5
  34. package/lib/solution/BaseSales/types.d.ts +2 -2
  35. package/lib/solution/BookingByStep/index.d.ts +1 -1
  36. package/lib/solution/ShopDiscount/index.d.ts +1 -0
  37. package/lib/solution/ShopDiscount/index.js +29 -3
  38. package/lib/solution/ShopDiscount/utils.d.ts +4 -2
  39. package/lib/solution/ShopDiscount/utils.js +39 -23
  40. package/package.json +1 -1
@@ -161,7 +161,7 @@ export declare function resolveManualOverrideLineOriginalPrice(params: {
161
161
  * // => -4
162
162
  */
163
163
  export declare function resolveEffectivePerUnitDiscount(product: Record<string, any>): number;
164
- export declare function createDefaultOrderRulesHooks(): RulesParamsHooks;
164
+ export declare function createDefaultOrderRulesHooks(getBookings?: () => OrderTempOrder['bookings']): RulesParamsHooks;
165
165
  /**
166
166
  * 通过 session 类商品的开始时间结束时间生成商品的时长
167
167
  * @param {CartItem} cartItem
@@ -23,11 +23,13 @@ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" !=
23
23
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
24
24
  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); }
25
25
  import dayjs from 'dayjs';
26
+ import customParseFormat from 'dayjs/plugin/customParseFormat';
26
27
  import Decimal from 'decimal.js';
27
28
  import { getProductHolderConfig } from "../Holder/utils";
28
29
  import { buildProductLineFingerprint, createEmptySummary } from "../../solution/ScanOrder/utils";
29
30
  import { createUuidV4 } from "./utils/orderCollectionIdentity";
30
31
  import { encodeSalesNotes } from "./salesNotes";
32
+ dayjs.extend(customParseFormat);
31
33
  var POINT_CARD_SNAPSHOT_TAG = 'point_card';
32
34
  var VIRTUAL_CURRENCY_SNAPSHOT_TAG = 'virtual_currency';
33
35
  function isPlainObject(value) {
@@ -731,14 +733,37 @@ export function resolveEffectivePerUnitDiscount(product) {
731
733
  if (!Number.isFinite(originalPrice) || !Number.isFinite(finalPrice)) return fromList;
732
734
  return fromList + (originalPrice - finalPrice);
733
735
  }
734
- export function createDefaultOrderRulesHooks() {
736
+ export function createDefaultOrderRulesHooks(getBookings) {
737
+ var getProductStartDate = function getProductStartDate(product) {
738
+ var _ref14, _product$metadata$uni, _product$metadata2, _ref15, _product$booking_uid, _product$metadata3, _product$metadata4, _product$metadata5, _product$metadata6;
739
+ var productUid = String((_ref14 = (_product$metadata$uni = (_product$metadata2 = product.metadata) === null || _product$metadata2 === void 0 ? void 0 : _product$metadata2.unique_identification_number) !== null && _product$metadata$uni !== void 0 ? _product$metadata$uni : product.unique_identification_number) !== null && _ref14 !== void 0 ? _ref14 : '');
740
+ var bookingUid = String((_ref15 = (_product$booking_uid = product.booking_uid) !== null && _product$booking_uid !== void 0 ? _product$booking_uid : (_product$metadata3 = product.metadata) === null || _product$metadata3 === void 0 ? void 0 : _product$metadata3.booking_uid) !== null && _ref15 !== void 0 ? _ref15 : '');
741
+ // 每次读取当前 bookings,覆盖改期、订单回显以及直接调用 Rules 的选券入口。
742
+ var bookings = (getBookings === null || getBookings === void 0 ? void 0 : getBookings()) || [];
743
+ var booking = bookings.find(function (item) {
744
+ var _ref16, _item$product_uid, _item$metadata3;
745
+ return productUid && String((_ref16 = (_item$product_uid = item === null || item === void 0 ? void 0 : item.product_uid) !== null && _item$product_uid !== void 0 ? _item$product_uid : item === null || item === void 0 || (_item$metadata3 = item.metadata) === null || _item$metadata3 === void 0 ? void 0 : _item$metadata3.product_uid) !== null && _ref16 !== void 0 ? _ref16 : '') === productUid;
746
+ }) || bookings.find(function (item) {
747
+ var _ref17, _item$metadata$unique, _item$metadata4;
748
+ return bookingUid && String((_ref17 = (_item$metadata$unique = item === null || item === void 0 || (_item$metadata4 = item.metadata) === null || _item$metadata4 === void 0 ? void 0 : _item$metadata4.unique_identification_number) !== null && _item$metadata$unique !== void 0 ? _item$metadata$unique : item === null || item === void 0 ? void 0 : item.booking_uid) !== null && _ref17 !== void 0 ? _ref17 : '') === bookingUid;
749
+ });
750
+ if (booking) {
751
+ // 严格解析并保留 Invalid Date,让公共时间校验拒绝缺失/非法时间,避免回退到当前时间。
752
+ return dayjs("".concat(booking.start_date, " ").concat(booking.start_time), ['YYYY-MM-DD HH:mm', 'YYYY-MM-DD HH:mm:ss', 'YYYY-MM-DD H:mm', 'YYYY-MM-DD H:mm:ss'], true);
753
+ }
754
+ if (getBookings && (bookingUid || product.booking_id || (_product$metadata4 = product.metadata) !== null && _product$metadata4 !== void 0 && _product$metadata4.booking_id)) {
755
+ return dayjs('');
756
+ }
757
+ var legacyStartDate = ((_product$metadata5 = product.metadata) === null || _product$metadata5 === void 0 ? void 0 : _product$metadata5.start_date) || ((_product$metadata6 = product.metadata) === null || _product$metadata6 === void 0 ? void 0 : _product$metadata6.startDate);
758
+ return legacyStartDate ? dayjs(legacyStartDate) : undefined;
759
+ };
735
760
  var toUnitPriceString = function toUnitPriceString(totalLike, num) {
736
761
  var effectiveNum = Number(num) > 0 ? Number(num) : 1;
737
762
  return new Decimal(Number(totalLike) || 0).dividedBy(effectiveNum).toDecimalPlaces(2).toString();
738
763
  };
739
764
  var getBundleIdentity = function getBundleIdentity(bundle) {
740
- var _ref14, _bundle$bundle_id, _ref15, _ref16, _bundle$bundle_produc, _ref17, _ref18, _bundle$bundle_varian, _ref19, _bundle$bundle_group_;
741
- return [(_ref14 = (_bundle$bundle_id = bundle.bundle_id) !== null && _bundle$bundle_id !== void 0 ? _bundle$bundle_id : bundle.id) !== null && _ref14 !== void 0 ? _ref14 : '', (_ref15 = (_ref16 = (_bundle$bundle_produc = bundle.bundle_product_id) !== null && _bundle$bundle_produc !== void 0 ? _bundle$bundle_produc : bundle._bundle_product_id) !== null && _ref16 !== void 0 ? _ref16 : bundle.product_id) !== null && _ref15 !== void 0 ? _ref15 : '', (_ref17 = (_ref18 = (_bundle$bundle_varian = bundle.bundle_variant_id) !== null && _bundle$bundle_varian !== void 0 ? _bundle$bundle_varian : bundle.variant_id) !== null && _ref18 !== void 0 ? _ref18 : bundle.product_variant_id) !== null && _ref17 !== void 0 ? _ref17 : 0, (_ref19 = (_bundle$bundle_group_ = bundle.bundle_group_id) !== null && _bundle$bundle_group_ !== void 0 ? _bundle$bundle_group_ : bundle.group_id) !== null && _ref19 !== void 0 ? _ref19 : ''].join('|');
765
+ var _ref18, _bundle$bundle_id, _ref19, _ref20, _bundle$bundle_produc, _ref21, _ref22, _bundle$bundle_varian, _ref23, _bundle$bundle_group_;
766
+ return [(_ref18 = (_bundle$bundle_id = bundle.bundle_id) !== null && _bundle$bundle_id !== void 0 ? _bundle$bundle_id : bundle.id) !== null && _ref18 !== void 0 ? _ref18 : '', (_ref19 = (_ref20 = (_bundle$bundle_produc = bundle.bundle_product_id) !== null && _bundle$bundle_produc !== void 0 ? _bundle$bundle_produc : bundle._bundle_product_id) !== null && _ref20 !== void 0 ? _ref20 : bundle.product_id) !== null && _ref19 !== void 0 ? _ref19 : '', (_ref21 = (_ref22 = (_bundle$bundle_varian = bundle.bundle_variant_id) !== null && _bundle$bundle_varian !== void 0 ? _bundle$bundle_varian : bundle.variant_id) !== null && _ref22 !== void 0 ? _ref22 : bundle.product_variant_id) !== null && _ref21 !== void 0 ? _ref21 : 0, (_ref23 = (_bundle$bundle_group_ = bundle.bundle_group_id) !== null && _bundle$bundle_group_ !== void 0 ? _bundle$bundle_group_ : bundle.group_id) !== null && _ref23 !== void 0 ? _ref23 : ''].join('|');
742
767
  };
743
768
  var mergeRulesBundlePrices = function mergeRulesBundlePrices(currentBundle, rulesBundle) {
744
769
  if (!Array.isArray(rulesBundle)) return rulesBundle;
@@ -748,7 +773,7 @@ export function createDefaultOrderRulesHooks() {
748
773
  currentByIdentity.set(getBundleIdentity(bundle), bundle);
749
774
  });
750
775
  return rulesBundle.map(function (bundle) {
751
- var _bundle$price_type_ex2, _ref20, _ref21, _current$price, _ref22, _ref23, _ref24, _current$original_pri;
776
+ var _bundle$price_type_ex2, _ref24, _ref25, _current$price, _ref26, _ref27, _ref28, _current$original_pri;
752
777
  if (!bundle || _typeof(bundle) !== 'object') return bundle;
753
778
  var current = currentByIdentity.get(getBundleIdentity(bundle));
754
779
  if (!current) return bundle;
@@ -757,8 +782,8 @@ export function createDefaultOrderRulesHooks() {
757
782
  } : {});
758
783
  var isProductPriceBundle = ((_bundle$price_type_ex2 = bundle.price_type_ext) !== null && _bundle$price_type_ex2 !== void 0 ? _bundle$price_type_ex2 : current.price_type_ext) === 'product_price';
759
784
  if (!isProductPriceBundle) return bundleWithDisplayFields;
760
- var sourcePrice = (_ref20 = (_ref21 = (_current$price = current.price) !== null && _current$price !== void 0 ? _current$price : current.custom_price) !== null && _ref21 !== void 0 ? _ref21 : current.original_price) !== null && _ref20 !== void 0 ? _ref20 : current.bundle_selling_price;
761
- var originalPrice = (_ref22 = (_ref23 = (_ref24 = (_current$original_pri = current.original_price) !== null && _current$original_pri !== void 0 ? _current$original_pri : current.product_price) !== null && _ref24 !== void 0 ? _ref24 : current.price) !== null && _ref23 !== void 0 ? _ref23 : current.custom_price) !== null && _ref22 !== void 0 ? _ref22 : sourcePrice;
785
+ var sourcePrice = (_ref24 = (_ref25 = (_current$price = current.price) !== null && _current$price !== void 0 ? _current$price : current.custom_price) !== null && _ref25 !== void 0 ? _ref25 : current.original_price) !== null && _ref24 !== void 0 ? _ref24 : current.bundle_selling_price;
786
+ var originalPrice = (_ref26 = (_ref27 = (_ref28 = (_current$original_pri = current.original_price) !== null && _current$original_pri !== void 0 ? _current$original_pri : current.product_price) !== null && _ref28 !== void 0 ? _ref28 : current.price) !== null && _ref27 !== void 0 ? _ref27 : current.custom_price) !== null && _ref26 !== void 0 ? _ref26 : sourcePrice;
762
787
  return _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, bundleWithDisplayFields), sourcePrice !== undefined ? {
763
788
  price: sourcePrice
764
789
  } : {}), originalPrice !== undefined ? {
@@ -770,7 +795,7 @@ export function createDefaultOrderRulesHooks() {
770
795
  };
771
796
  return {
772
797
  getProduct: function getProduct(product) {
773
- var _product$metadata2, _product$metadata3, _product$metadata4, _product$metadata5, _product$metadata6, _metadataAny$_promoti;
798
+ var _product$metadata7, _product$metadata8, _product$metadata9, _metadataAny$_promoti;
774
799
  // source_product_price 是权威源;兜底链:source → mainSelling − options(反推)→ 行 selling_price
775
800
  var metadataAny = product.metadata || {};
776
801
  var optionSum = sumOptionUnitPrice(getProductSkuOptions(product));
@@ -797,7 +822,7 @@ export function createDefaultOrderRulesHooks() {
797
822
  // 否则同 SKU 不同小料会在 calcDiscount 重组时互相覆盖。
798
823
  // 不透明 identity 契约下,normalizeOrderProduct / hydrate 已保证唯一值存在;
799
824
  // 留 fingerprint 分支仅作 Rules 单测里直接传裸 product 时的兜底。
800
- _id: (_product$metadata2 = product.metadata) !== null && _product$metadata2 !== void 0 && _product$metadata2.unique_identification_number ? "".concat(product.product_id, "_").concat(product.product_variant_id, "_").concat(product.metadata.unique_identification_number) : "".concat(product.product_id, "_").concat(product.product_variant_id, "_").concat(buildProductLineFingerprint(getProductSkuOptions(product), product.product_bundle)),
825
+ _id: (_product$metadata7 = product.metadata) !== null && _product$metadata7 !== void 0 && _product$metadata7.unique_identification_number ? "".concat(product.product_id, "_").concat(product.product_variant_id, "_").concat(product.metadata.unique_identification_number) : "".concat(product.product_id, "_").concat(product.product_variant_id, "_").concat(buildProductLineFingerprint(getProductSkuOptions(product), product.product_bundle)),
801
826
  // Rules 内部 getProductTotalPrice / getProductOriginTotalPrice 会各自再叠加 bundle + option,
802
827
  // 所以这里必须喂 source-level(不含 option、不含 bundle、不含折扣)单价,避免双加 option。
803
828
  price: sourcePrice,
@@ -809,23 +834,23 @@ export function createDefaultOrderRulesHooks() {
809
834
  num: product.num || 1,
810
835
  discount_list: product.discount_list || [],
811
836
  bundle: product.product_bundle || [],
812
- booking_id: ((_product$metadata3 = product.metadata) === null || _product$metadata3 === void 0 ? void 0 : _product$metadata3.booking_id) || null,
837
+ booking_id: ((_product$metadata8 = product.metadata) === null || _product$metadata8 === void 0 ? void 0 : _product$metadata8.booking_id) || null,
813
838
  isClient: false,
814
839
  // 勿写死 false:否则 Rules 不会走 total≠origin_total 的手动价推断,
815
840
  // 无券时会把 bundle 价还原成 original_price(手动改价套餐会从 20 回到 30)。
816
841
  isManualDiscount: resolveRulesManualDiscountFlag(metadataAny),
817
- holder_id: (_product$metadata4 = product.metadata) === null || _product$metadata4 === void 0 ? void 0 : _product$metadata4.holder_id,
818
- startDate: ((_product$metadata5 = product.metadata) === null || _product$metadata5 === void 0 ? void 0 : _product$metadata5.start_date) || ((_product$metadata6 = product.metadata) === null || _product$metadata6 === void 0 ? void 0 : _product$metadata6.startDate),
842
+ holder_id: (_product$metadata9 = product.metadata) === null || _product$metadata9 === void 0 ? void 0 : _product$metadata9.holder_id,
843
+ startDate: getProductStartDate(product),
819
844
  main_product_selling_price: metadataAny.main_product_selling_price !== undefined ? new Decimal(Number(metadataAny.main_product_selling_price) || 0).minus(optionSum).toDecimalPlaces(2).toString() : undefined,
820
845
  inPromotion: ((_metadataAny$_promoti = metadataAny._promotion) === null || _metadataAny$_promoti === void 0 ? void 0 : _metadataAny$_promoti.inPromotion) === true,
821
846
  _promotion: metadataAny._promotion
822
847
  };
823
848
  },
824
849
  setProduct: function setProduct(product, values) {
825
- var _ref25, _values$quantity, _ref26, _metadataAny$source_p, _values$discount_list, _values$quantity2;
826
- var nextNum = Number((_ref25 = (_values$quantity = values.quantity) !== null && _values$quantity !== void 0 ? _values$quantity : product.num) !== null && _ref25 !== void 0 ? _ref25 : 1) || 1;
850
+ var _ref29, _values$quantity, _ref30, _metadataAny$source_p, _values$discount_list, _values$quantity2;
851
+ var nextNum = Number((_ref29 = (_values$quantity = values.quantity) !== null && _values$quantity !== void 0 ? _values$quantity : product.num) !== null && _ref29 !== void 0 ? _ref29 : 1) || 1;
827
852
  var metadataAny = product.metadata || {};
828
- var existedSource = (_ref26 = (_metadataAny$source_p = metadataAny.source_product_price) !== null && _metadataAny$source_p !== void 0 ? _metadataAny$source_p : product.selling_price) !== null && _ref26 !== void 0 ? _ref26 : '0';
853
+ var existedSource = (_ref30 = (_metadataAny$source_p = metadataAny.source_product_price) !== null && _metadataAny$source_p !== void 0 ? _metadataAny$source_p : product.selling_price) !== null && _ref30 !== void 0 ? _ref30 : '0';
829
854
  var nextOptions = getProductSkuOptions(product);
830
855
  var optionSum = sumOptionUnitPrice(nextOptions);
831
856
 
@@ -1035,7 +1060,7 @@ function formatSubmitBundleItems(bundle) {
1035
1060
  var formatOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1036
1061
  if (!Array.isArray(bundle)) return [];
1037
1062
  return bundle.map(function (b) {
1038
- var _ref27, _rawBundle$price, _rawBundle$surcharge_, _rawBundle$num, _rawBundle$is_charge_, _rawBundle$bundle_var, _rawBundle$quantity, _rawBundle$extension_, _rawBundle$extension_2, _ref28, _rawBundle$price_type, _ref29, _rawBundle$price_type2, _rawBundle$bundle_gro, _rawBundle$bundle_id, _rawBundle$bundle_pro;
1063
+ var _ref31, _rawBundle$price, _rawBundle$surcharge_, _rawBundle$num, _rawBundle$is_charge_, _rawBundle$bundle_var, _rawBundle$quantity, _rawBundle$extension_, _rawBundle$extension_2, _ref32, _rawBundle$price_type, _ref33, _rawBundle$price_type2, _rawBundle$bundle_gro, _rawBundle$bundle_id, _rawBundle$bundle_pro;
1039
1064
  var rawBundle = b && _typeof(b) === 'object' ? b : {};
1040
1065
  var existedMetadata = rawBundle.metadata && _typeof(rawBundle.metadata) === 'object' ? rawBundle.metadata : {};
1041
1066
  var _customProductBundleMapId = existedMetadata.custom_product_bundle_map_id,
@@ -1046,7 +1071,7 @@ function formatSubmitBundleItems(bundle) {
1046
1071
  var sellingPrice = formatOptions.virtualSettlementMode ? '0.00' : getBundleSellingMagnitude(rawBundle).toFixed(2);
1047
1072
  // payment 价由整单折扣均摊层产出;缺省(无折扣)时与 selling 净额同义。
1048
1073
  var paymentPrice = formatOptions.virtualSettlementMode ? '0.00' : rawBundle.bundle_payment_price !== undefined && rawBundle.bundle_payment_price !== null && rawBundle.bundle_payment_price !== '' ? toMoneyString(rawBundle.bundle_payment_price) : sellingPrice;
1049
- var priceValue = formatOptions.virtualSettlementMode ? 0 : (_ref27 = (_rawBundle$price = rawBundle.price) !== null && _rawBundle$price !== void 0 ? _rawBundle$price : rawBundle.custom_price) !== null && _ref27 !== void 0 ? _ref27 : rawBundle.bundle_selling_price;
1074
+ var priceValue = formatOptions.virtualSettlementMode ? 0 : (_ref31 = (_rawBundle$price = rawBundle.price) !== null && _rawBundle$price !== void 0 ? _rawBundle$price : rawBundle.custom_price) !== null && _ref31 !== void 0 ? _ref31 : rawBundle.bundle_selling_price;
1050
1075
  var relationSurchargeIds = Array.isArray(rawBundle.relation_surcharge_ids) ? rawBundle.relation_surcharge_ids : Array.isArray(existedMetadata.relation_surcharge_ids) ? existedMetadata.relation_surcharge_ids : [];
1051
1076
  var surchargeFee = toMoneyString((_rawBundle$surcharge_ = rawBundle.surcharge_fee) !== null && _rawBundle$surcharge_ !== void 0 ? _rawBundle$surcharge_ : existedMetadata.surcharge_fee);
1052
1077
  var productDiscountDifference = toBundleNumber(existedMetadata.product_discount_difference, 0);
@@ -1065,8 +1090,8 @@ function formatSubmitBundleItems(bundle) {
1065
1090
  extension_id: (_rawBundle$extension_ = rawBundle.extension_id) !== null && _rawBundle$extension_ !== void 0 ? _rawBundle$extension_ : 0,
1066
1091
  extension_type: (_rawBundle$extension_2 = rawBundle.extension_type) !== null && _rawBundle$extension_2 !== void 0 ? _rawBundle$extension_2 : 'normal',
1067
1092
  price: priceValue,
1068
- price_type: (_ref28 = (_rawBundle$price_type = rawBundle.price_type) !== null && _rawBundle$price_type !== void 0 ? _rawBundle$price_type : rawBundle.custom_price_type) !== null && _ref28 !== void 0 ? _ref28 : '',
1069
- price_type_ext: (_ref29 = (_rawBundle$price_type2 = rawBundle.price_type_ext) !== null && _rawBundle$price_type2 !== void 0 ? _rawBundle$price_type2 : rawBundle.custom_price_type_ext) !== null && _ref29 !== void 0 ? _ref29 : '',
1093
+ price_type: (_ref32 = (_rawBundle$price_type = rawBundle.price_type) !== null && _rawBundle$price_type !== void 0 ? _rawBundle$price_type : rawBundle.custom_price_type) !== null && _ref32 !== void 0 ? _ref32 : '',
1094
+ price_type_ext: (_ref33 = (_rawBundle$price_type2 = rawBundle.price_type_ext) !== null && _rawBundle$price_type2 !== void 0 ? _rawBundle$price_type2 : rawBundle.custom_price_type_ext) !== null && _ref33 !== void 0 ? _ref33 : '',
1070
1095
  bundle_selling_price: sellingPrice,
1071
1096
  bundle_payment_price: paymentPrice,
1072
1097
  option: formatSubmitOptionItems(rawBundle.option, formatOptions),
@@ -1102,11 +1127,11 @@ function formatSubmitBundleItems(bundle) {
1102
1127
  * 法币仅做字段/metadata 裁剪;虚拟币在出站前再次执行零加价与固定单价断言。
1103
1128
  */
1104
1129
  function normalizeSubmitProduct(product) {
1105
- var _ref31, _submitProduct$bundle, _rawMetadata$product_, _rawMetadata$selected, _rawMetadata$selected2, _submitProduct$produc, _submitProduct$paymen;
1130
+ var _ref35, _submitProduct$bundle, _rawMetadata$product_, _rawMetadata$selected, _rawMetadata$selected2, _submitProduct$produc, _submitProduct$paymen;
1106
1131
  var formatOptions = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1107
- var _ref30 = product,
1108
- _runtimeUid = _ref30.unique_identification_number,
1109
- submitProduct = _objectWithoutProperties(_ref30, _excluded2);
1132
+ var _ref34 = product,
1133
+ _runtimeUid = _ref34.unique_identification_number,
1134
+ submitProduct = _objectWithoutProperties(_ref34, _excluded2);
1110
1135
  var num = submitProduct.num,
1111
1136
  _productSurchargeFee = submitProduct.surcharge_fee,
1112
1137
  _deprecatedDiscountAmount = submitProduct.discount_amount,
@@ -1123,7 +1148,7 @@ function normalizeSubmitProduct(product) {
1123
1148
  // 兼容历史 BigSale 编辑链路:bundle_edit 曾被写入 metadata,
1124
1149
  // 出站时需提升到商品顶层;套餐未编辑时也必须显式提交 0。
1125
1150
  var hasProductBundle = Array.isArray(submitProduct.product_bundle) && submitProduct.product_bundle.length > 0;
1126
- var bundleEdit = (_ref31 = (_submitProduct$bundle = submitProduct.bundle_edit) !== null && _submitProduct$bundle !== void 0 ? _submitProduct$bundle : rawMetadata.bundle_edit) !== null && _ref31 !== void 0 ? _ref31 : hasProductBundle ? 0 : undefined;
1151
+ var bundleEdit = (_ref35 = (_submitProduct$bundle = submitProduct.bundle_edit) !== null && _submitProduct$bundle !== void 0 ? _submitProduct$bundle : rawMetadata.bundle_edit) !== null && _ref35 !== void 0 ? _ref35 : hasProductBundle ? 0 : undefined;
1127
1152
  var cleanMetadata = {};
1128
1153
  if (rawMetadata.unique_identification_number) {
1129
1154
  cleanMetadata.unique_identification_number = rawMetadata.unique_identification_number;
@@ -1354,7 +1379,7 @@ export function resolveSubmitOrderType(params) {
1354
1379
  return 'virtual';
1355
1380
  }
1356
1381
  export function buildSubmitPayload(params) {
1357
- var _tempOrder$metadata2, _tempOrder$customer_i, _tempOrder$country_ca, _tempOrder$phone, _tempOrder$email, _tempOrder$order_numb, _tempOrder$shop_order, _tempOrder$shop_full_, _ref33, _tempOrder$is_price_i, _tempOrder$is_deposit, _tempOrder$_extend, _enhancedPayload$summ;
1382
+ var _tempOrder$metadata2, _tempOrder$customer_i, _tempOrder$country_ca, _tempOrder$phone, _tempOrder$email, _tempOrder$order_numb, _tempOrder$shop_order, _tempOrder$shop_full_, _ref37, _tempOrder$is_price_i, _tempOrder$is_deposit, _tempOrder$_extend, _enhancedPayload$summ;
1358
1383
  var tempOrder = params.tempOrder,
1359
1384
  cacheId = params.cacheId,
1360
1385
  _params$now = params.now,
@@ -1368,29 +1393,29 @@ export function buildSubmitPayload(params) {
1368
1393
  var scheduleDate = tempOrder.schedule_date || tempOrder.created_at || formatDateTime(now);
1369
1394
  var bookingUuid = createUuidV4();
1370
1395
  var virtualSettlementMode = ((_tempOrder$metadata2 = tempOrder.metadata) === null || _tempOrder$metadata2 === void 0 || (_tempOrder$metadata2 = _tempOrder$metadata2.currency_settlement_config) === null || _tempOrder$metadata2 === void 0 ? void 0 : _tempOrder$metadata2.settlement_type) === 'virtual_currency';
1371
- var _ref32 = tempOrder,
1372
- _extend = _ref32._extend,
1373
- _relationId = _ref32.relation_id,
1374
- _tableFormId = _ref32.table_form_id,
1375
- _resourceId = _ref32.resource_id,
1376
- _summary = _ref32.summary,
1377
- _lastOrderInfo = _ref32.lastOrderInfo,
1378
- _paidAmount = _ref32.paid_amount,
1379
- _shopId = _ref32.shop_id,
1380
- _shopNote = _ref32.shop_note,
1381
- _shopServiceType = _ref32.shop_service_type,
1382
- _startTime = _ref32.start_time,
1383
- _customer = _ref32.customer,
1384
- _discountList = _ref32.discount_list,
1385
- _orderMetaList = _ref32.order_meta_list,
1386
- _rootTaxFee = _ref32.tax_fee,
1387
- _totalAmount = _ref32.total_amount,
1388
- _totalRefundAmount = _ref32.total_refund_amount,
1389
- _createDate = _ref32.create_date,
1390
- _holderId = _ref32.holder_id,
1391
- _paymentStatus = _ref32.payment_status,
1392
- _notes = _ref32.notes,
1393
- tempOrderRest = _objectWithoutProperties(_ref32, _excluded4);
1396
+ var _ref36 = tempOrder,
1397
+ _extend = _ref36._extend,
1398
+ _relationId = _ref36.relation_id,
1399
+ _tableFormId = _ref36.table_form_id,
1400
+ _resourceId = _ref36.resource_id,
1401
+ _summary = _ref36.summary,
1402
+ _lastOrderInfo = _ref36.lastOrderInfo,
1403
+ _paidAmount = _ref36.paid_amount,
1404
+ _shopId = _ref36.shop_id,
1405
+ _shopNote = _ref36.shop_note,
1406
+ _shopServiceType = _ref36.shop_service_type,
1407
+ _startTime = _ref36.start_time,
1408
+ _customer = _ref36.customer,
1409
+ _discountList = _ref36.discount_list,
1410
+ _orderMetaList = _ref36.order_meta_list,
1411
+ _rootTaxFee = _ref36.tax_fee,
1412
+ _totalAmount = _ref36.total_amount,
1413
+ _totalRefundAmount = _ref36.total_refund_amount,
1414
+ _createDate = _ref36.create_date,
1415
+ _holderId = _ref36.holder_id,
1416
+ _paymentStatus = _ref36.payment_status,
1417
+ _notes = _ref36.notes,
1418
+ tempOrderRest = _objectWithoutProperties(_ref36, _excluded4);
1394
1419
  var resolvedBusinessCode = businessCode !== null && businessCode !== void 0 ? businessCode : tempOrder.business_code;
1395
1420
  var normalizedOrderMetaList = normalizeOrderMetaList(tempOrder.order_meta_list);
1396
1421
  var submitType = resolveSubmitOrderType({
@@ -1415,7 +1440,7 @@ export function buildSubmitPayload(params) {
1415
1440
  type: submitType,
1416
1441
  business_code: resolvedBusinessCode,
1417
1442
  sales_channel: tempOrder.sales_channel || 'my_pisel',
1418
- order_sales_channel: (_ref33 = channel !== null && channel !== void 0 ? channel : tempOrder.order_sales_channel) !== null && _ref33 !== void 0 ? _ref33 : 'online_store',
1443
+ order_sales_channel: (_ref37 = channel !== null && channel !== void 0 ? channel : tempOrder.order_sales_channel) !== null && _ref37 !== void 0 ? _ref37 : 'online_store',
1419
1444
  status: tempOrder.status || 'normal'
1420
1445
  }, params.includePaymentStatus !== false ? {
1421
1446
  payment_status: tempOrder.payment_status || 'payment_processing'
@@ -1443,13 +1468,13 @@ export function buildSubmitPayload(params) {
1443
1468
  // holder: tempOrder.holder || null,
1444
1469
  summary: summary || tempOrder.summary || createEmptySummary(),
1445
1470
  metadata: function () {
1446
- var _ref34 = tempOrder.metadata || {},
1447
- _collectPax = _ref34.collect_pax,
1448
- _tableOccupancyDuration = _ref34.table_occupancy_duration,
1449
- _cartSettlementKey = _ref34.cart_settlement_key,
1450
- _cartSettlementSnapshot = _ref34.cart_settlement_snapshot,
1451
- _legalCurrencySnapshot = _ref34.legal_currency_snapshot,
1452
- rest = _objectWithoutProperties(_ref34, _excluded5);
1471
+ var _ref38 = tempOrder.metadata || {},
1472
+ _collectPax = _ref38.collect_pax,
1473
+ _tableOccupancyDuration = _ref38.table_occupancy_duration,
1474
+ _cartSettlementKey = _ref38.cart_settlement_key,
1475
+ _cartSettlementSnapshot = _ref38.cart_settlement_snapshot,
1476
+ _legalCurrencySnapshot = _ref38.legal_currency_snapshot,
1477
+ rest = _objectWithoutProperties(_ref38, _excluded5);
1453
1478
  return _objectSpread({}, rest);
1454
1479
  }()
1455
1480
  }, (_tempOrder$_extend = tempOrder._extend) !== null && _tempOrder$_extend !== void 0 && (_tempOrder$_extend = _tempOrder$_extend.salesNotesState) !== null && _tempOrder$_extend !== void 0 && _tempOrder$_extend.dirty ? {
@@ -1653,9 +1678,9 @@ export function clearTempOrderHolderAssignments(tempOrder) {
1653
1678
  * getOrderProductLineUid({ metadata: { unique_identification_number: 'line-1' } }); // 'line-1'
1654
1679
  */
1655
1680
  export function getOrderProductLineUid(product) {
1656
- var _product$metadata$uni, _product$metadata7;
1681
+ var _product$metadata$uni2, _product$metadata10;
1657
1682
  if (!product || _typeof(product) !== 'object') return null;
1658
- var uid = (_product$metadata$uni = (_product$metadata7 = product.metadata) === null || _product$metadata7 === void 0 ? void 0 : _product$metadata7.unique_identification_number) !== null && _product$metadata$uni !== void 0 ? _product$metadata$uni : product.unique_identification_number;
1683
+ var uid = (_product$metadata$uni2 = (_product$metadata10 = product.metadata) === null || _product$metadata10 === void 0 ? void 0 : _product$metadata10.unique_identification_number) !== null && _product$metadata$uni2 !== void 0 ? _product$metadata$uni2 : product.unique_identification_number;
1659
1684
  if (uid === undefined || uid === null || uid === '') return null;
1660
1685
  return String(uid);
1661
1686
  }
@@ -1666,8 +1691,8 @@ export function getRuntimeProductOrigin(tempOrder, product) {
1666
1691
  return tempOrder._extend.productsByUid[uid].origin;
1667
1692
  }
1668
1693
  var matchedProduct = ((tempOrder === null || tempOrder === void 0 ? void 0 : tempOrder.products) || []).find(function (item) {
1669
- var _ref35, _item$product_id, _ref36, _product$product_id;
1670
- return item === product || getOrderProductLineUid(item) === uid || String((_ref35 = (_item$product_id = item === null || item === void 0 ? void 0 : item.product_id) !== null && _item$product_id !== void 0 ? _item$product_id : item === null || item === void 0 ? void 0 : item.id) !== null && _ref35 !== void 0 ? _ref35 : '') === String((_ref36 = (_product$product_id = product === null || product === void 0 ? void 0 : product.product_id) !== null && _product$product_id !== void 0 ? _product$product_id : product === null || product === void 0 ? void 0 : product.id) !== null && _ref36 !== void 0 ? _ref36 : '');
1694
+ var _ref39, _item$product_id, _ref40, _product$product_id;
1695
+ return item === product || getOrderProductLineUid(item) === uid || String((_ref39 = (_item$product_id = item === null || item === void 0 ? void 0 : item.product_id) !== null && _item$product_id !== void 0 ? _item$product_id : item === null || item === void 0 ? void 0 : item.id) !== null && _ref39 !== void 0 ? _ref39 : '') === String((_ref40 = (_product$product_id = product === null || product === void 0 ? void 0 : product.product_id) !== null && _product$product_id !== void 0 ? _product$product_id : product === null || product === void 0 ? void 0 : product.id) !== null && _ref40 !== void 0 ? _ref40 : '');
1671
1696
  });
1672
1697
  var matchedUid = matchedProduct ? getOrderProductLineUid(matchedProduct) : '';
1673
1698
  return matchedUid ? (tempOrder === null || tempOrder === void 0 || (_tempOrder$_extend4 = tempOrder._extend) === null || _tempOrder$_extend4 === void 0 || (_tempOrder$_extend4 = _tempOrder$_extend4.productsByUid) === null || _tempOrder$_extend4 === void 0 || (_tempOrder$_extend4 = _tempOrder$_extend4[matchedUid]) === null || _tempOrder$_extend4 === void 0 ? void 0 : _tempOrder$_extend4.origin) || null : null;
@@ -49,5 +49,5 @@ export declare class Product extends BaseModule implements Module {
49
49
  getCategories(): ProductCategory[];
50
50
  setOtherParams(key: string, value: any): void;
51
51
  getOtherParams(): any;
52
- getProductType(): "normal" | "duration" | "session";
52
+ getProductType(): "duration" | "session" | "normal";
53
53
  }
@@ -36,7 +36,7 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
36
36
  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); }
37
37
  import { BaseModule } from "../BaseModule";
38
38
  import { UnavailableReason } from "./types";
39
- import { uniqueById, getDiscountAmount, getDiscountListAmountTotal, getDiscountListAmount, filterDiscountListByBookingTime } from "../../solution/ShopDiscount/utils";
39
+ import { uniqueById, getDiscountAmount, getDiscountListAmountTotal, getDiscountListAmount, filterDiscountListByBookingTime, getDiscountTimeUnavailableReason } from "../../solution/ShopDiscount/utils";
40
40
  import { getProductOriginTotalPrice, getProductTotalPrice } from "../Cart/utils";
41
41
  import Decimal from 'decimal.js';
42
42
  import { isBoolean } from 'lodash-es';
@@ -44,6 +44,7 @@ import dayjs from 'dayjs';
44
44
  import { isOrderLevelFixedAmountDiscount } from "../../solution/ShopDiscount/utils";
45
45
  import { calculateOrderLevelDiscountAllocation } from "../../solution/ShopDiscount/utils";
46
46
  import { compareEntitlementPassPriority, getRemainingEntitlementUses, isEntitlementPass, isFullCoveragePass, resolveEntitlementQuota } from "../Discount/entitlementPass";
47
+ import { getDiscountUsageBlockReason, getDiscountUsageLimitFailKey } from "../Discount/availability";
47
48
  export var RulesModule = /*#__PURE__*/function (_BaseModule) {
48
49
  _inherits(RulesModule, _BaseModule);
49
50
  var _super = _createSuper(RulesModule);
@@ -402,7 +403,12 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
402
403
  if (discount.isEditMode) {
403
404
  editModeDiscount.push(discount);
404
405
  } else {
405
- addModeDiscount.push(discount);
406
+ // 试算不能把 config / 不可用原因写回原有选券;每次重新计算以清除旧原因。
407
+ addModeDiscount.push(_objectSpread(_objectSpread({}, discount), {}, {
408
+ usageLimitFailKey: getDiscountUsageLimitFailKey(discount),
409
+ reason: undefined,
410
+ reasonCode: getDiscountUsageBlockReason(discount)
411
+ }));
406
412
  }
407
413
  });
408
414
 
@@ -664,12 +670,19 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
664
670
 
665
671
  // 🔥 为每个折扣卡/商品券执行策略检查并附加config
666
672
  var evaluator = this.getWalletPassEvaluator();
673
+ addModeDiscount.forEach(function (discount) {
674
+ if (discount.reasonCode) discount.config = {
675
+ isAvailable: false
676
+ };
677
+ });
667
678
  if (evaluator) {
668
679
  addModeDiscount.forEach(function (discount) {
680
+ // 即使没有匹配的动态策略,服务端状态和次数限制也不能被覆盖为可用。
681
+ if (discount.reasonCode) return;
669
682
  var discountType = discount.tag || discount.type || '';
670
683
  // 对两类全额抵扣卡和折扣卡执行附加策略检查。
671
684
  if (['entitlement_pass', 'good_pass', 'discount_card', 'product_discount_card'].includes(discountType)) {
672
- var _discount$limited_rel, _discount$limited_rel2;
685
+ var _discount$unified_ava, _discount$limited_rel, _discount$limited_rel2;
673
686
  var entitlementQuota = isEntitlementPass(discount) ? resolveEntitlementQuota(discount) : null;
674
687
  if (isEntitlementPass(discount) && !entitlementQuota) {
675
688
  discount.config = {
@@ -685,7 +698,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
685
698
  balance: (entitlementQuota === null || entitlementQuota === void 0 ? void 0 : entitlementQuota.type) === 'unlimited' ? Number.MAX_SAFE_INTEGER : (entitlementQuota === null || entitlementQuota === void 0 ? void 0 : entitlementQuota.type) === 'limited' ? entitlementQuota.balance : Number(discount.balance || 0),
686
699
  type: discountType,
687
700
  product_id: discount.product_id,
688
- unified_available_status: 1,
701
+ unified_available_status: (_discount$unified_ava = discount.unified_available_status) !== null && _discount$unified_ava !== void 0 ? _discount$unified_ava : 1,
689
702
  available_product_type: (_discount$limited_rel = discount.limited_relation_product_data) === null || _discount$limited_rel === void 0 ? void 0 : _discount$limited_rel.type,
690
703
  available_product_ids: (_discount$limited_rel2 = discount.limited_relation_product_data) === null || _discount$limited_rel2 === void 0 ? void 0 : _discount$limited_rel2.product_ids
691
704
  };
@@ -718,6 +731,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
718
731
  discount.config = {
719
732
  isAvailable: false
720
733
  };
734
+ discount.reason = result.reason;
735
+ discount.reasonCode = result.reasonCode || 'not_meet_the_required_conditions';
721
736
  }
722
737
  }
723
738
  });
@@ -894,6 +909,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
894
909
 
895
910
  // 记录每个优惠券适用的商品详细信息
896
911
  var discountApplicableProducts = new Map();
912
+ var discountTimeReasons = new Map();
913
+ var discountHolderMismatch = new Set();
897
914
 
898
915
  // 初始化每个优惠券的适用性和可抵扣商品
899
916
  addModeDiscount.forEach(function (discount) {
@@ -913,7 +930,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
913
930
 
914
931
  // 辅助函数:检查商品是否对某个折扣卡可用
915
932
  var checkItemApplicableForDiscount = function checkItemApplicableForDiscount(flatItem, discount) {
916
- var _product, _product2, _product3, _flatItem$bundleItem, _flatItem$bundleItem2, _product4;
933
+ var _discount$config2, _product, _product2, _product3, _flatItem$bundleItem, _flatItem$bundleItem2, _product4;
934
+ if (((_discount$config2 = discount.config) === null || _discount$config2 === void 0 ? void 0 : _discount$config2.isAvailable) === false) return false;
917
935
  var product;
918
936
  if (flatItem.type === 'main') {
919
937
  product = flatItem.product;
@@ -1121,7 +1139,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1121
1139
  }
1122
1140
  var isItemRewardProductDiscount = _this4.isItemRewardProductDiscount(product);
1123
1141
  addModeDiscount.forEach(function (discount) {
1124
- var _product5, _product6, _product7, _product8, _flatItem$bundleItem3, _flatItem$bundleItem4, _discount$config2;
1142
+ var _product5, _product6, _product7, _product8, _flatItem$bundleItem3, _flatItem$bundleItem4, _discount$config3;
1125
1143
  var limitedData = discount === null || discount === void 0 ? void 0 : discount.limited_relation_product_data;
1126
1144
  // 拿到discount配置的holder信息 product信息 product.holder 加在 isLimitedProduct
1127
1145
  var _tempVar = (flatItem === null || flatItem === void 0 ? void 0 : flatItem.type) === 'bundle' ? flatItem === null || flatItem === void 0 ? void 0 : flatItem.parentProduct : flatItem === null || flatItem === void 0 ? void 0 : flatItem.product;
@@ -1129,10 +1147,11 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1129
1147
  isNeedHolder: resolveIsFormSubject(_tempVar) && !(_tempVar !== null && _tempVar !== void 0 && _tempVar.isNormalProduct),
1130
1148
  holder_id: (_tempVar === null || _tempVar === void 0 ? void 0 : _tempVar.holder_id) || product.holder_id
1131
1149
  }, holders);
1132
- var timeLimit = true;
1133
- timeLimit = !!filterDiscountListByBookingTime([discount], (((_product5 = product) === null || _product5 === void 0 ? void 0 : _product5.startDate) || dayjs()).format('YYYY-MM-DD HH:mm:ss')).length;
1150
+ var timeReason = getDiscountTimeUnavailableReason(discount, (((_product5 = product) === null || _product5 === void 0 ? void 0 : _product5.startDate) || dayjs()).format('YYYY-MM-DD HH:mm:ss'));
1151
+ var timeLimit = !timeReason;
1134
1152
  // 是符合折扣的商品
1135
- var isLimitedProduct = (limitedData.type === 'product_all' && limitedData.filter !== 1 || limitedData.type === 'product_all' && limitedData.filter === 1 && !limitedData.exclude_product_ids.includes(product.id) || limitedData.product_ids && limitedData.product_ids.includes(product.id)) && isHolderMatch;
1153
+ var isProductInScope = limitedData.type === 'product_all' && limitedData.filter !== 1 || limitedData.type === 'product_all' && limitedData.filter === 1 && !limitedData.exclude_product_ids.includes(product.id) || limitedData.product_ids && limitedData.product_ids.includes(product.id);
1154
+ var isLimitedProduct = isProductInScope && isHolderMatch;
1136
1155
 
1137
1156
  // 编辑的商品 使用了优惠券不可用
1138
1157
  var isAvailableProduct = flatItem.type === 'main' ? !((_product6 = product) !== null && _product6 !== void 0 && _product6.booking_id && (_product7 = product) !== null && _product7 !== void 0 && (_product7 = _product7.discount_list) !== null && _product7 !== void 0 && _product7.length && (_product8 = product) !== null && _product8 !== void 0 && (_product8 = _product8.discount_list) !== null && _product8 !== void 0 && _product8.every(function (discount) {
@@ -1143,9 +1162,15 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1143
1162
 
1144
1163
  // 套餐是否可用判断
1145
1164
  var isBundleAvailable = _this4.checkPackageSubItemUsageRules(discount, flatItem);
1165
+ if (isProductInScope && isBundleAvailable && !isItemRewardProductDiscount) {
1166
+ var timeReasons = discountTimeReasons.get(discount.id) || [];
1167
+ timeReasons.push(timeReason);
1168
+ discountTimeReasons.set(discount.id, timeReasons);
1169
+ if (!isHolderMatch && timeLimit) discountHolderMismatch.add(discount.id);
1170
+ }
1146
1171
 
1147
1172
  // 判断优惠券是否适用于该商品
1148
- if (isAvailableProduct && !isItemRewardProductDiscount && isLimitedProduct && timeLimit && isBundleAvailable && (_discount$config2 = discount.config) !== null && _discount$config2 !== void 0 && _discount$config2.isAvailable && (!isEntitlementPass(discount) || getRemainingEntitlementUses(discount, 0, 1) > 0)) {
1173
+ if (isAvailableProduct && !isItemRewardProductDiscount && isLimitedProduct && timeLimit && isBundleAvailable && (_discount$config3 = discount.config) !== null && _discount$config3 !== void 0 && _discount$config3.isAvailable && (!isEntitlementPass(discount) || getRemainingEntitlementUses(discount, 0, 1) > 0)) {
1149
1174
  var _discountApplicabilit, _discount$metadata4, _discount$metadata5;
1150
1175
  // 记录此优惠券适用的商品
1151
1176
  (_discountApplicabilit = discountApplicability.get(discount.id)) === null || _discountApplicabilit === void 0 || _discountApplicabilit.push(product.id);
@@ -1301,9 +1326,9 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1301
1326
  if (!discount.isSelected) return false;
1302
1327
  }
1303
1328
  if (['entitlement_pass', 'good_pass', 'discount_card', 'product_discount_card'].includes(discountType) && !isReapplyEditModeDiscountForProduct) {
1304
- var _discount$config3;
1329
+ var _discount$config4;
1305
1330
  // 如果策略检查后没有config,说明不可用
1306
- if (discount.config === undefined || !(discount !== null && discount !== void 0 && (_discount$config3 = discount.config) !== null && _discount$config3 !== void 0 && _discount$config3.isAvailable)) {
1331
+ if (discount.config === undefined || !(discount !== null && discount !== void 0 && (_discount$config4 = discount.config) !== null && _discount$config4 !== void 0 && _discount$config4.isAvailable)) {
1307
1332
  return false;
1308
1333
  }
1309
1334
  }
@@ -1328,8 +1353,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
1328
1353
 
1329
1354
  // 🔥 检查 maxUsagePerOrder 限制:同一 product_id 的商品券使用数量不能超过配置值
1330
1355
  if (isFullCoveragePass(discount)) {
1331
- var _discount$config4;
1332
- var maxUsagePerOrder = (_discount$config4 = discount.config) === null || _discount$config4 === void 0 ? void 0 : _discount$config4.maxUsagePerOrder;
1356
+ var _discount$config5;
1357
+ var maxUsagePerOrder = (_discount$config5 = discount.config) === null || _discount$config5 === void 0 ? void 0 : _discount$config5.maxUsagePerOrder;
1333
1358
  if (maxUsagePerOrder && maxUsagePerOrder > 0) {
1334
1359
  var currentUsedCount = usedProductIdCounts.get(discount.product_id) || 0;
1335
1360
  if (currentUsedCount >= maxUsagePerOrder) {
@@ -2351,10 +2376,17 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
2351
2376
 
2352
2377
  // 根据是否有适用商品决定isAvailable
2353
2378
  var isAvailable = applicableProducts.length > 0;
2379
+ var timeReasons = discountTimeReasons.get(discount.id) || [];
2380
+ var timeReason = timeReasons.length ? timeReasons.every(Boolean) ? timeReasons[0] : undefined : getDiscountTimeUnavailableReason(discount, dayjs().format('YYYY-MM-DD HH:mm:ss'));
2381
+ var reasonCode = isAvailable ? undefined : getDiscountUsageBlockReason(discount) || timeReason || discount.reasonCode || (discountHolderMismatch.has(discount.id) ? 'holder_not_matched' : 'product_not_applicable');
2382
+ var availabilityReason = {
2383
+ reasonCode: reasonCode,
2384
+ reason: reasonCode && reasonCode === discount.reasonCode ? discount.reason : undefined
2385
+ };
2354
2386
 
2355
2387
  // 如果此优惠券被明确设置为不选中,保持其状态,但正确设置isAvailable
2356
2388
  if (typeof discount.isSelected === 'boolean' && discount.isSelected === false && discount.isManualSelect) {
2357
- return _objectSpread(_objectSpread({}, discount), {}, {
2389
+ return _objectSpread(_objectSpread(_objectSpread({}, discount), availabilityReason), {}, {
2358
2390
  isSelected: false,
2359
2391
  isAvailable: isAvailable,
2360
2392
  // 正确设置可用性
@@ -2367,6 +2399,8 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
2367
2399
  }
2368
2400
  if (isDiscountUsed(discount)) {
2369
2401
  return _objectSpread(_objectSpread({}, discount), {}, {
2402
+ reason: undefined,
2403
+ reasonCode: undefined,
2370
2404
  isSelected: true,
2371
2405
  isManualSelect: options !== null && options !== void 0 && options.scan ? false : discount.isManualSelect,
2372
2406
  // 标记为可用,因为它已被应用
@@ -2387,7 +2421,7 @@ export var RulesModule = /*#__PURE__*/function (_BaseModule) {
2387
2421
  } else if (!appliedProductDetails.length && !committedAppliedProductDetails.length) {
2388
2422
  isSelected = false;
2389
2423
  }
2390
- return _objectSpread(_objectSpread({}, discount), {}, {
2424
+ return _objectSpread(_objectSpread(_objectSpread({}, discount), availabilityReason), {}, {
2391
2425
  // 如果有适用的商品,标记为可用
2392
2426
  isAvailable: isAvailable,
2393
2427
  isSelected: isSelected,
@@ -441,10 +441,10 @@ export interface BaseSalesAddLogParams extends BaseSalesLogInput {
441
441
  /** BaseSales.scanPromotionCode 对外的轻量结果(UI 可用 getDiscountList 或 scannedDiscountList 补 Holder) */
442
442
  export interface BaseSalesScanCodeResult {
443
443
  isAvailable: boolean;
444
- /** 卡券已加入 Promotion;false 时可能是无效、过期或已使用。 */
444
+ /** 卡券已加入 Promotion;可能因次数、时间或当前订单条件而暂时无法应用。 */
445
445
  isAccepted?: boolean;
446
446
  type?: 'server' | string;
447
447
  unavailableReason?: 'time_limit' | string;
448
- /** batchSearch 原始结果;Holder 补全等流程可从这里读取原始卡券。 */
448
+ /** 扫码卡券资料及最新可用状态,供 Holder 补全等流程使用。 */
449
449
  scannedDiscountList?: Discount[];
450
450
  }
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
326
326
  date: string;
327
327
  status: string;
328
328
  week: string;
329
- weekNum: 0 | 2 | 1 | 6 | 4 | 5 | 3;
329
+ weekNum: 0 | 1 | 2 | 3 | 4 | 5 | 6;
330
330
  }[]>;
331
331
  submitTimeSlot(timeSlots: TimeSliceItem): void;
332
332
  private getScheduleDataByIds;
@@ -43,6 +43,7 @@ export declare class ShopDiscountImpl extends BaseModule implements Module {
43
43
  batchSearchByProductIds(productIds: number[]): Promise<Discount[]>;
44
44
  scanCode(code: string, customerId?: number): Promise<{
45
45
  isAvailable: boolean;
46
+ isAccepted?: boolean;
46
47
  productList: Record<string, any>[];
47
48
  discountList: Discount[];
48
49
  type: "server" | "clientCalc";