@pisell/pisellos 2.1.150 → 2.1.151

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 (201) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +1 -0
  3. package/dist/model/strategy/adapter/promotion/evaluator.js +99 -26
  4. package/dist/model/strategy/adapter/walletPass/evaluator.d.ts +2 -0
  5. package/dist/model/strategy/adapter/walletPass/evaluator.js +61 -8
  6. package/dist/model/strategy/adapter/walletPass/locales.js +12 -3
  7. package/dist/model/strategy/engine.d.ts +18 -5
  8. package/dist/model/strategy/engine.js +145 -45
  9. package/dist/model/strategy/type.d.ts +17 -0
  10. package/dist/model/strategy/type.js +4 -0
  11. package/dist/modules/Cart/types.d.ts +2 -0
  12. package/dist/modules/Cart/utils/cartProduct.js +56 -25
  13. package/dist/modules/Discount/index.d.ts +2 -6
  14. package/dist/modules/Discount/index.js +8 -14
  15. package/dist/modules/Discount/types.d.ts +19 -1
  16. package/dist/modules/Order/index.d.ts +1 -65
  17. package/dist/modules/Order/index.js +30 -901
  18. package/dist/modules/Order/types.d.ts +12 -174
  19. package/dist/modules/Order/types.js +0 -2
  20. package/dist/modules/Order/utils.d.ts +0 -118
  21. package/dist/modules/Order/utils.js +2 -586
  22. package/dist/modules/Payment/index.d.ts +2 -1
  23. package/dist/modules/Payment/index.js +10 -7
  24. package/dist/modules/Payment/utils.js +3 -0
  25. package/dist/modules/Payment/walletpass.d.ts +23 -0
  26. package/dist/modules/Payment/walletpass.js +191 -95
  27. package/dist/modules/Product/utils.js +2 -2
  28. package/dist/modules/ProductList/index.d.ts +1 -1
  29. package/dist/modules/ProductList/index.js +3 -4
  30. package/dist/modules/Rules/index.d.ts +9 -5
  31. package/dist/modules/Rules/index.js +677 -168
  32. package/dist/modules/Rules/types.d.ts +2 -0
  33. package/dist/modules/Schedule/getDateIsInSchedule.js +18 -11
  34. package/dist/modules/Schedule/utils.d.ts +1 -1
  35. package/dist/modules/Summary/types.d.ts +2 -0
  36. package/dist/modules/Summary/utils.d.ts +9 -3
  37. package/dist/modules/Summary/utils.js +52 -41
  38. package/dist/modules/index.d.ts +0 -4
  39. package/dist/modules/index.js +1 -5
  40. package/dist/plugins/window.d.ts +2 -0
  41. package/dist/solution/BookingByStep/index.d.ts +3 -2
  42. package/dist/solution/BookingByStep/index.js +43 -46
  43. package/dist/solution/BookingByStep/types.d.ts +1 -3
  44. package/dist/solution/BookingByStep/types.js +1 -5
  45. package/dist/solution/BookingByStep/utils/timeslots.d.ts +1 -3
  46. package/dist/solution/BookingByStep/utils/timeslots.js +12 -19
  47. package/dist/solution/Checkout/index.js +2 -0
  48. package/dist/solution/ShopDiscount/index.d.ts +2 -2
  49. package/dist/solution/ShopDiscount/index.js +41 -37
  50. package/dist/solution/ShopDiscount/types.d.ts +1 -1
  51. package/dist/solution/ShopDiscount/types.js +2 -1
  52. package/dist/solution/ShopDiscount/utils.js +26 -12
  53. package/dist/solution/index.d.ts +0 -2
  54. package/dist/solution/index.js +1 -3
  55. package/lib/index.d.ts +1 -0
  56. package/lib/index.js +3 -1
  57. package/lib/model/strategy/adapter/promotion/evaluator.js +57 -8
  58. package/lib/model/strategy/adapter/promotion/index.js +49 -0
  59. package/lib/model/strategy/adapter/walletPass/evaluator.d.ts +2 -0
  60. package/lib/model/strategy/adapter/walletPass/evaluator.js +34 -3
  61. package/lib/model/strategy/adapter/walletPass/locales.js +12 -3
  62. package/lib/model/strategy/engine.d.ts +18 -5
  63. package/lib/model/strategy/engine.js +85 -21
  64. package/lib/model/strategy/type.d.ts +17 -0
  65. package/lib/modules/Cart/types.d.ts +2 -0
  66. package/lib/modules/Cart/utils/cartProduct.js +39 -12
  67. package/lib/modules/Discount/index.d.ts +2 -6
  68. package/lib/modules/Discount/index.js +1 -3
  69. package/lib/modules/Discount/types.d.ts +19 -1
  70. package/lib/modules/Order/index.d.ts +1 -65
  71. package/lib/modules/Order/index.js +1 -513
  72. package/lib/modules/Order/types.d.ts +12 -174
  73. package/lib/modules/Order/utils.d.ts +0 -118
  74. package/lib/modules/Order/utils.js +2 -483
  75. package/lib/modules/Payment/index.d.ts +2 -1
  76. package/lib/modules/Payment/index.js +1 -0
  77. package/lib/modules/Payment/utils.js +3 -0
  78. package/lib/modules/Payment/walletpass.d.ts +23 -0
  79. package/lib/modules/Payment/walletpass.js +94 -17
  80. package/lib/modules/Product/utils.js +2 -2
  81. package/lib/modules/ProductList/index.d.ts +1 -1
  82. package/lib/modules/ProductList/index.js +3 -5
  83. package/lib/modules/Rules/index.d.ts +9 -5
  84. package/lib/modules/Rules/index.js +780 -288
  85. package/lib/modules/Rules/types.d.ts +2 -0
  86. package/lib/modules/Schedule/getDateIsInSchedule.js +11 -9
  87. package/lib/modules/Schedule/utils.d.ts +1 -1
  88. package/lib/modules/Summary/types.d.ts +2 -0
  89. package/lib/modules/Summary/utils.d.ts +9 -3
  90. package/lib/modules/Summary/utils.js +31 -22
  91. package/lib/modules/index.d.ts +0 -4
  92. package/lib/modules/index.js +1 -9
  93. package/lib/plugins/window.d.ts +2 -0
  94. package/lib/solution/BookingByStep/index.d.ts +3 -2
  95. package/lib/solution/BookingByStep/index.js +4 -6
  96. package/lib/solution/BookingByStep/types.d.ts +1 -3
  97. package/lib/solution/BookingByStep/types.js +0 -10
  98. package/lib/solution/BookingByStep/utils/timeslots.d.ts +1 -3
  99. package/lib/solution/BookingByStep/utils/timeslots.js +11 -19
  100. package/lib/solution/Checkout/index.js +2 -0
  101. package/lib/solution/ShopDiscount/index.d.ts +2 -2
  102. package/lib/solution/ShopDiscount/index.js +24 -16
  103. package/lib/solution/ShopDiscount/types.d.ts +1 -1
  104. package/lib/solution/ShopDiscount/utils.js +10 -6
  105. package/lib/solution/index.d.ts +0 -2
  106. package/lib/solution/index.js +1 -5
  107. package/package.json +1 -1
  108. package/dist/apis/picoding.d.ts +0 -0
  109. package/dist/apis/picoding.js +0 -1
  110. package/dist/modules/OpenData/index.d.ts +0 -24
  111. package/dist/modules/OpenData/index.js +0 -173
  112. package/dist/modules/OpenData/types.d.ts +0 -73
  113. package/dist/modules/OpenData/types.js +0 -1
  114. package/dist/modules/OpenData/utils.d.ts +0 -2
  115. package/dist/modules/OpenData/utils.js +0 -75
  116. package/dist/modules/Quotation/index.d.ts +0 -48
  117. package/dist/modules/Quotation/index.js +0 -248
  118. package/dist/modules/Quotation/types.d.ts +0 -42
  119. package/dist/modules/Quotation/types.js +0 -1
  120. package/dist/modules/SalesSummary/index.d.ts +0 -63
  121. package/dist/modules/SalesSummary/index.js +0 -174
  122. package/dist/modules/SalesSummary/types.d.ts +0 -60
  123. package/dist/modules/SalesSummary/types.js +0 -1
  124. package/dist/modules/SalesSummary/utils.d.ts +0 -30
  125. package/dist/modules/SalesSummary/utils.js +0 -480
  126. package/dist/modules/ScanOrderLogger/index.d.ts +0 -23
  127. package/dist/modules/ScanOrderLogger/index.js +0 -174
  128. package/dist/modules/ScanOrderLogger/providers/feishu.d.ts +0 -2
  129. package/dist/modules/ScanOrderLogger/providers/feishu.js +0 -221
  130. package/dist/modules/ScanOrderLogger/providers/grafana.d.ts +0 -2
  131. package/dist/modules/ScanOrderLogger/providers/grafana.js +0 -50
  132. package/dist/modules/ScanOrderLogger/types.d.ts +0 -53
  133. package/dist/modules/ScanOrderLogger/types.js +0 -1
  134. package/dist/solution/ScanOrder/index.d.ts +0 -152
  135. package/dist/solution/ScanOrder/index.js +0 -3132
  136. package/dist/solution/ScanOrder/types.d.ts +0 -287
  137. package/dist/solution/ScanOrder/types.js +0 -35
  138. package/dist/solution/ScanOrder/utils.d.ts +0 -167
  139. package/dist/solution/ScanOrder/utils.js +0 -764
  140. package/dist/solution/VenueBooking/index.d.ts +0 -199
  141. package/dist/solution/VenueBooking/index.js +0 -3459
  142. package/dist/solution/VenueBooking/sales-section-4-annotated.json +0 -343
  143. package/dist/solution/VenueBooking/types.d.ts +0 -154
  144. package/dist/solution/VenueBooking/types.js +0 -21
  145. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +0 -11
  146. package/dist/solution/VenueBooking/utils/dateSummary.js +0 -104
  147. package/dist/solution/VenueBooking/utils/resource.d.ts +0 -14
  148. package/dist/solution/VenueBooking/utils/resource.js +0 -131
  149. package/dist/solution/VenueBooking/utils/slotMerge.d.ts +0 -38
  150. package/dist/solution/VenueBooking/utils/slotMerge.js +0 -239
  151. package/dist/solution/VenueBooking/utils/timeSlot.d.ts +0 -32
  152. package/dist/solution/VenueBooking/utils/timeSlot.js +0 -453
  153. package/dist/solution/VenueBooking/utils.d.ts +0 -1
  154. package/dist/solution/VenueBooking/utils.js +0 -1
  155. package/lib/apis/picoding.d.ts +0 -0
  156. package/lib/apis/picoding.js +0 -0
  157. package/lib/modules/OpenData/index.d.ts +0 -24
  158. package/lib/modules/OpenData/index.js +0 -119
  159. package/lib/modules/OpenData/types.d.ts +0 -73
  160. package/lib/modules/OpenData/types.js +0 -17
  161. package/lib/modules/OpenData/utils.d.ts +0 -2
  162. package/lib/modules/OpenData/utils.js +0 -111
  163. package/lib/modules/Quotation/index.d.ts +0 -48
  164. package/lib/modules/Quotation/index.js +0 -152
  165. package/lib/modules/Quotation/types.d.ts +0 -42
  166. package/lib/modules/Quotation/types.js +0 -17
  167. package/lib/modules/SalesSummary/index.d.ts +0 -63
  168. package/lib/modules/SalesSummary/index.js +0 -105
  169. package/lib/modules/SalesSummary/types.d.ts +0 -60
  170. package/lib/modules/SalesSummary/types.js +0 -17
  171. package/lib/modules/SalesSummary/utils.d.ts +0 -30
  172. package/lib/modules/SalesSummary/utils.js +0 -420
  173. package/lib/modules/ScanOrderLogger/index.d.ts +0 -23
  174. package/lib/modules/ScanOrderLogger/index.js +0 -147
  175. package/lib/modules/ScanOrderLogger/providers/feishu.d.ts +0 -2
  176. package/lib/modules/ScanOrderLogger/providers/feishu.js +0 -157
  177. package/lib/modules/ScanOrderLogger/providers/grafana.d.ts +0 -2
  178. package/lib/modules/ScanOrderLogger/providers/grafana.js +0 -52
  179. package/lib/modules/ScanOrderLogger/types.d.ts +0 -53
  180. package/lib/modules/ScanOrderLogger/types.js +0 -17
  181. package/lib/solution/ScanOrder/index.d.ts +0 -152
  182. package/lib/solution/ScanOrder/index.js +0 -1901
  183. package/lib/solution/ScanOrder/types.d.ts +0 -287
  184. package/lib/solution/ScanOrder/types.js +0 -36
  185. package/lib/solution/ScanOrder/utils.d.ts +0 -167
  186. package/lib/solution/ScanOrder/utils.js +0 -635
  187. package/lib/solution/VenueBooking/index.d.ts +0 -199
  188. package/lib/solution/VenueBooking/index.js +0 -1926
  189. package/lib/solution/VenueBooking/sales-section-4-annotated.json +0 -343
  190. package/lib/solution/VenueBooking/types.d.ts +0 -154
  191. package/lib/solution/VenueBooking/types.js +0 -44
  192. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +0 -11
  193. package/lib/solution/VenueBooking/utils/dateSummary.js +0 -110
  194. package/lib/solution/VenueBooking/utils/resource.d.ts +0 -14
  195. package/lib/solution/VenueBooking/utils/resource.js +0 -92
  196. package/lib/solution/VenueBooking/utils/slotMerge.d.ts +0 -38
  197. package/lib/solution/VenueBooking/utils/slotMerge.js +0 -237
  198. package/lib/solution/VenueBooking/utils/timeSlot.d.ts +0 -32
  199. package/lib/solution/VenueBooking/utils/timeSlot.js +0 -339
  200. package/lib/solution/VenueBooking/utils.d.ts +0 -1
  201. package/lib/solution/VenueBooking/utils.js +0 -69
@@ -8,10 +8,12 @@ export declare class WalletPassEvaluator {
8
8
  private engine;
9
9
  private strategyConfigs;
10
10
  private locale;
11
+ private otherParams;
11
12
  constructor();
12
13
  setStrategyConfigs(strategyConfigs: StrategyConfig[]): void;
13
14
  getStrategyConfigs(): StrategyConfig[];
14
15
  setLocale(locale: string): void;
16
+ setOtherParams(otherParams: any): void;
15
17
  getText(key: string): string;
16
18
  /**
17
19
  * 搜索券的格式
@@ -45,10 +45,27 @@ var defaultStrategyMetadataCustom = {
45
45
  maxPassesPerItem: 0,
46
46
  deductOptionPrice: false
47
47
  };
48
+ var FIELD_REASON_CODE_MAP = {
49
+ orderTotalAmount: "order_total_amount_not_enough",
50
+ applicableProductTotalAmount: "applicable_product_total_amount_not_enough",
51
+ applicableProductCount: "applicable_product_count_not_enough"
52
+ };
53
+ var AMOUNT_FIELDS = /* @__PURE__ */ new Set([
54
+ "orderTotalAmount",
55
+ "applicableProductTotalAmount"
56
+ ]);
57
+ function formatReason(template, value, currency = "") {
58
+ if (!template)
59
+ return template;
60
+ const v = value === void 0 || value === null ? "" : String(value);
61
+ const c = currency === void 0 || currency === null ? "" : String(currency);
62
+ return template.replace(/\$\{value\}/g, () => v).replace(/\{value\}/g, () => v).replace(/\{currency\}/g, () => c);
63
+ }
48
64
  var WalletPassEvaluator = class {
49
65
  constructor() {
50
66
  this.strategyConfigs = [];
51
67
  this.locale = "en";
68
+ this.otherParams = {};
52
69
  this.engine = new import__.StrategyEngine({
53
70
  debug: false,
54
71
  enableTrace: false
@@ -64,6 +81,9 @@ var WalletPassEvaluator = class {
64
81
  setLocale(locale) {
65
82
  this.locale = locale;
66
83
  }
84
+ setOtherParams(otherParams) {
85
+ this.otherParams = otherParams;
86
+ }
67
87
  getText(key) {
68
88
  var _a, _b;
69
89
  return (_b = (_a = import_locales.locales) == null ? void 0 : _a[this.locale]) == null ? void 0 : _b[key];
@@ -101,7 +121,7 @@ var WalletPassEvaluator = class {
101
121
  * 评估可用的 vouchers
102
122
  */
103
123
  evaluate(input) {
104
- var _a, _b;
124
+ var _a, _b, _c, _d, _e, _f, _g;
105
125
  const { orderTotalAmount, products, vouchers, strategyConfigs } = input;
106
126
  const productIds = products.map((p) => p.product_id);
107
127
  const results = [];
@@ -176,7 +196,13 @@ var WalletPassEvaluator = class {
176
196
  });
177
197
  } else {
178
198
  let reasonCode = "not_meet_the_required_conditions";
179
- if (evaluationResult.code) {
199
+ let thresholdValue = void 0;
200
+ const failedField = (_c = evaluationResult.matched) == null ? void 0 : _c.failedField;
201
+ const failedRule = (_e = (_d = evaluationResult.matched) == null ? void 0 : _d.failedRules) == null ? void 0 : _e[0];
202
+ if (failedField && FIELD_REASON_CODE_MAP[failedField]) {
203
+ reasonCode = FIELD_REASON_CODE_MAP[failedField];
204
+ thresholdValue = failedRule == null ? void 0 : failedRule.value;
205
+ } else if (evaluationResult.code) {
180
206
  const codeMapping = {
181
207
  INSUFFICIENT_AMOUNT: "not_meet_the_required_conditions",
182
208
  USAGE_LIMIT_EXCEEDED: "usage_limit_reached",
@@ -186,6 +212,10 @@ var WalletPassEvaluator = class {
186
212
  };
187
213
  reasonCode = codeMapping[evaluationResult.code] || "not_meet_the_required_conditions";
188
214
  }
215
+ const rawText = this.getText(reasonCode);
216
+ const currency = failedField && AMOUNT_FIELDS.has(failedField) ? ((_g = (_f = this.otherParams) == null ? void 0 : _f.getData) == null ? void 0 : _g.call(_f, "shop_symbol")) || "" : "";
217
+ console.log(currency, "currency12345");
218
+ const reason = thresholdValue !== void 0 ? formatReason(rawText, thresholdValue, currency) : rawText;
189
219
  results.push({
190
220
  voucher,
191
221
  isApplicable: false,
@@ -193,7 +223,7 @@ var WalletPassEvaluator = class {
193
223
  maxDeduction: 0,
194
224
  deductTaxAndFee: false,
195
225
  applicableProductIds: [],
196
- reason: this.getText(reasonCode),
226
+ reason,
197
227
  reasonCode,
198
228
  strategyResult: evaluationResult
199
229
  });
@@ -386,6 +416,7 @@ var WalletPassEvaluator = class {
386
416
  * 计算适用商品的总金额和数量
387
417
  */
388
418
  calculateApplicableProducts(products, applicableProductIds, deductTaxAndFee) {
419
+ console.log(products, "products1234");
389
420
  let total = 0;
390
421
  let count = 0;
391
422
  if (applicableProductIds !== null && applicableProductIds.length === 0) {
@@ -29,7 +29,10 @@ var locales = {
29
29
  "usage_limit_reached": "已达到使用次数上限",
30
30
  "max_passes_per_item_reached": "该商品已达到卡券使用上限",
31
31
  "not_available_for_this_channel": "当前渠道不可使用",
32
- "not_valid_for_this_order_type": "当前订单类型不适用"
32
+ "not_valid_for_this_order_type": "当前订单类型不适用",
33
+ "order_total_amount_not_enough": "满 {currency}{value} 可用",
34
+ "applicable_product_total_amount_not_enough": "满 {currency}{value} 可用",
35
+ "applicable_product_count_not_enough": "至少 {value} 件"
33
36
  },
34
37
  "en": {
35
38
  "not_meet_the_required_conditions": "Not meet the required conditions.",
@@ -37,7 +40,10 @@ var locales = {
37
40
  "usage_limit_reached": "Usage limit reached.",
38
41
  "max_passes_per_item_reached": "Max passes per item reached.",
39
42
  "not_available_for_this_channel": "Not available for this channel.",
40
- "not_valid_for_this_order_type": "Not valid for this order type."
43
+ "not_valid_for_this_order_type": "Not valid for this order type.",
44
+ "order_total_amount_not_enough": "Spend {currency}{value} to use",
45
+ "applicable_product_total_amount_not_enough": "Spend {currency}{value} to use",
46
+ "applicable_product_count_not_enough": "Min. Qty {value}"
41
47
  },
42
48
  "zh-HK": {
43
49
  "not_meet_the_required_conditions": "未達使用條件",
@@ -45,7 +51,10 @@ var locales = {
45
51
  "usage_limit_reached": "已達使用次數上限",
46
52
  "max_passes_per_item_reached": "該商品已達卡券使用上限",
47
53
  "not_available_for_this_channel": "當前渠道不可使用",
48
- "not_valid_for_this_order_type": "當前訂單類型不適用"
54
+ "not_valid_for_this_order_type": "當前訂單類型不適用",
55
+ "order_total_amount_not_enough": "滿 {currency}{value} 可用",
56
+ "applicable_product_total_amount_not_enough": "滿 {currency}{value} 可用",
57
+ "applicable_product_count_not_enough": "至少 {value} 件"
49
58
  }
50
59
  };
51
60
  // Annotate the CommonJS export names for ESM import in node:
@@ -27,17 +27,30 @@ export declare class StrategyEngine {
27
27
  *
28
28
  * @param group 条件组
29
29
  * @param context 运行时上下文
30
- * @returns 评估结果对象,包含条件是否满足和收集到的 actionIds
30
+ * @returns 评估结果对象,包含条件是否满足、收集到的 actionIds、以及失败的原子规则信息
31
31
  */
32
32
  private evaluateConditionGroup;
33
33
  /**
34
- * 评估条件组的逻辑运算
34
+ * 评估条件组的逻辑运算(带失败规则收集)
35
+ *
36
+ * 失败规则收集策略:
37
+ * - `and`:返回第一个失败的原子规则(嵌套 group 递归取其首个失败原子规则)
38
+ * - `or`:所有分支失败时,聚合每个分支的失败规则
39
+ * - `not`:被取反规则实际通过时,记录该规则
40
+ */
41
+ private evaluateGroupLogicDetailed;
42
+ /**
43
+ * 评估单个规则(带失败规则收集)
44
+ */
45
+ private evaluateRuleDetailed;
46
+ /**
47
+ * 评估原子规则(不收集失败信息,仅返回布尔结果)
35
48
  */
36
- private evaluateGroupLogic;
49
+ private evaluateAtomicRule;
37
50
  /**
38
- * 评估单个规则
51
+ * 构建失败规则信息
39
52
  */
40
- private evaluateRule;
53
+ private buildFailedRuleInfo;
41
54
  /**
42
55
  * 评估代码模式条件
43
56
  */
@@ -42,7 +42,7 @@ var StrategyEngine = class {
42
42
  * 评估策略
43
43
  */
44
44
  evaluate(config, context) {
45
- var _a;
45
+ var _a, _b;
46
46
  const startTime = Date.now();
47
47
  const trace = {
48
48
  steps: [],
@@ -105,7 +105,11 @@ var StrategyEngine = class {
105
105
  matched: {
106
106
  conditions: applicable,
107
107
  actionIds: evaluationResult.actionIds,
108
- details: {}
108
+ details: {},
109
+ ...applicable ? {} : {
110
+ failedField: (_a = evaluationResult.failedRules[0]) == null ? void 0 : _a.field,
111
+ failedRules: evaluationResult.failedRules
112
+ }
109
113
  },
110
114
  matchedActions: sortedActions,
111
115
  outputs: {},
@@ -119,7 +123,7 @@ var StrategyEngine = class {
119
123
  } catch (error) {
120
124
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
121
125
  if (this.options.enableTrace) {
122
- (_a = trace.errors) == null ? void 0 : _a.push({
126
+ (_b = trace.errors) == null ? void 0 : _b.push({
123
127
  step: "evaluation",
124
128
  error: errorMessage,
125
129
  timestamp: Date.now()
@@ -149,12 +153,15 @@ var StrategyEngine = class {
149
153
  *
150
154
  * @param group 条件组
151
155
  * @param context 运行时上下文
152
- * @returns 评估结果对象,包含条件是否满足和收集到的 actionIds
156
+ * @returns 评估结果对象,包含条件是否满足、收集到的 actionIds、以及失败的原子规则信息
153
157
  */
154
158
  evaluateConditionGroup(group, context) {
155
159
  const collectedActionIds = [];
156
- const isCurrentLayerSatisfied = this.evaluateGroupLogic(group, context);
157
- if (isCurrentLayerSatisfied) {
160
+ const { satisfied, failedRules } = this.evaluateGroupLogicDetailed(
161
+ group,
162
+ context
163
+ );
164
+ if (satisfied) {
158
165
  collectedActionIds.push(...group.actionIds);
159
166
  for (const rule of group.rules) {
160
167
  if (this.isConditionGroup(rule)) {
@@ -164,41 +171,98 @@ var StrategyEngine = class {
164
171
  }
165
172
  }
166
173
  return {
167
- satisfied: isCurrentLayerSatisfied,
168
- actionIds: collectedActionIds
174
+ satisfied,
175
+ actionIds: collectedActionIds,
176
+ failedRules
169
177
  };
170
178
  }
171
179
  /**
172
- * 评估条件组的逻辑运算
180
+ * 评估条件组的逻辑运算(带失败规则收集)
181
+ *
182
+ * 失败规则收集策略:
183
+ * - `and`:返回第一个失败的原子规则(嵌套 group 递归取其首个失败原子规则)
184
+ * - `or`:所有分支失败时,聚合每个分支的失败规则
185
+ * - `not`:被取反规则实际通过时,记录该规则
173
186
  */
174
- evaluateGroupLogic(group, context) {
187
+ evaluateGroupLogicDetailed(group, context) {
175
188
  const { operator, rules } = group;
176
189
  switch (operator) {
177
- case "and":
178
- return rules.every((rule) => this.evaluateRule(rule, context));
179
- case "or":
180
- return rules.some((rule) => this.evaluateRule(rule, context));
181
- case "not":
182
- if (rules.length === 0)
183
- return false;
184
- return !this.evaluateRule(rules[0], context);
190
+ case "and": {
191
+ for (const rule of rules) {
192
+ const ruleResult = this.evaluateRuleDetailed(rule, context);
193
+ if (!ruleResult.satisfied) {
194
+ return {
195
+ satisfied: false,
196
+ failedRules: ruleResult.failedRules
197
+ };
198
+ }
199
+ }
200
+ return { satisfied: true, failedRules: [] };
201
+ }
202
+ case "or": {
203
+ const aggregated = [];
204
+ for (const rule of rules) {
205
+ const ruleResult = this.evaluateRuleDetailed(rule, context);
206
+ if (ruleResult.satisfied) {
207
+ return { satisfied: true, failedRules: [] };
208
+ }
209
+ aggregated.push(...ruleResult.failedRules);
210
+ }
211
+ return { satisfied: false, failedRules: aggregated };
212
+ }
213
+ case "not": {
214
+ if (rules.length === 0) {
215
+ return { satisfied: false, failedRules: [] };
216
+ }
217
+ const ruleResult = this.evaluateRuleDetailed(rules[0], context);
218
+ if (ruleResult.satisfied) {
219
+ const failed = this.isConditionGroup(rules[0]) ? [] : [this.buildFailedRuleInfo(rules[0], context)];
220
+ return { satisfied: false, failedRules: failed };
221
+ }
222
+ return { satisfied: true, failedRules: [] };
223
+ }
185
224
  default:
186
225
  throw new Error(`Unknown operator: ${operator}`);
187
226
  }
188
227
  }
189
228
  /**
190
- * 评估单个规则
229
+ * 评估单个规则(带失败规则收集)
191
230
  */
192
- evaluateRule(rule, context) {
231
+ evaluateRuleDetailed(rule, context) {
193
232
  if (this.isConditionGroup(rule)) {
194
- return this.evaluateGroupLogic(rule, context);
233
+ return this.evaluateGroupLogicDetailed(rule, context);
195
234
  }
196
235
  const conditionRule = rule;
236
+ const satisfied = this.evaluateAtomicRule(conditionRule, context);
237
+ if (satisfied) {
238
+ return { satisfied: true, failedRules: [] };
239
+ }
240
+ return {
241
+ satisfied: false,
242
+ failedRules: [this.buildFailedRuleInfo(conditionRule, context)]
243
+ };
244
+ }
245
+ /**
246
+ * 评估原子规则(不收集失败信息,仅返回布尔结果)
247
+ */
248
+ evaluateAtomicRule(conditionRule, context) {
197
249
  if (conditionRule.type === "code" && conditionRule.code) {
198
250
  return this.evaluateCodeCondition(conditionRule.code, context);
199
251
  }
200
252
  return this.evaluateOperatorCondition(conditionRule, context);
201
253
  }
254
+ /**
255
+ * 构建失败规则信息
256
+ */
257
+ buildFailedRuleInfo(conditionRule, context) {
258
+ const actualValue = conditionRule.field ? this.getFieldValue(conditionRule.field, context) : void 0;
259
+ return {
260
+ field: conditionRule.field,
261
+ operator: conditionRule.operator,
262
+ value: conditionRule.value,
263
+ actualValue
264
+ };
265
+ }
202
266
  /**
203
267
  * 评估代码模式条件
204
268
  */
@@ -165,6 +165,23 @@ export interface MatchedInfo {
165
165
  actionIds: string[];
166
166
  /** 详细匹配信息 */
167
167
  details: Record<string, any>;
168
+ /** 顶层第一个失败的 field(仅在 conditions=false 时存在,便于直接消费) */
169
+ failedField?: string;
170
+ /** 失败的原子规则列表(仅在 conditions=false 时存在;or 全失败时可能有多条) */
171
+ failedRules?: FailedRuleInfo[];
172
+ }
173
+ /**
174
+ * 失败规则信息
175
+ */
176
+ export interface FailedRuleInfo {
177
+ /** 字段名 */
178
+ field?: string;
179
+ /** 运算符 */
180
+ operator?: string;
181
+ /** 配置的比较值(阈值) */
182
+ value?: any;
183
+ /** 实际取到的字段值 */
184
+ actualValue?: any;
168
185
  }
169
186
  /**
170
187
  * 执行轨迹
@@ -75,6 +75,8 @@ export interface CartItem {
75
75
  summaryTotal?: number | string;
76
76
  /** 商品原价总价,排除原始价格为0的场景 */
77
77
  origin_total?: number | string;
78
+ /** 基于 origin_total 乘以 商品数量的价格 */
79
+ summaryOriginTotal?: number | string;
78
80
  /** 商品数量 */
79
81
  num?: number;
80
82
  /** 商品图片 */
@@ -46,6 +46,18 @@ var import_decimal = __toESM(require("decimal.js"));
46
46
  var import_utils = require("../../Product/utils");
47
47
  var import_utils2 = require("../../../solution/ShopDiscount/utils");
48
48
  var import_utils3 = require("../../Summary/utils");
49
+ var toDiscountPayload = (discountItem) => {
50
+ var _a, _b;
51
+ return {
52
+ amount: discountItem.amount,
53
+ tag: discountItem.type,
54
+ par_value: (_a = discountItem.discount) == null ? void 0 : _a.percent,
55
+ config: discountItem.config,
56
+ metadata: {
57
+ discount_card_type: (_b = discountItem == null ? void 0 : discountItem.discount) == null ? void 0 : _b.discount_card_type
58
+ }
59
+ };
60
+ };
49
61
  var handleVariantProduct = (product) => {
50
62
  var _a;
51
63
  if (product == null ? void 0 : product.product_variant_id) {
@@ -90,6 +102,14 @@ var formatProductToCartItem = (params) => {
90
102
  num,
91
103
  discounts
92
104
  });
105
+ const origin_total = getProductTotalPrice({
106
+ product: cartItem._productInit || cartItem._productOrigin,
107
+ bundle,
108
+ options,
109
+ num,
110
+ discounts: []
111
+ });
112
+ cartItem.summaryOriginTotal = (origin_total || 0) * (num || 1);
93
113
  cartItem.image = product == null ? void 0 : product.cover;
94
114
  cartItem.like_status = "common";
95
115
  cartItem.duration = product == null ? void 0 : product.duration;
@@ -184,17 +204,24 @@ var formatProductToCartItemOrigin = (params) => {
184
204
  var getProductTotalPrice = (params) => {
185
205
  const { product, bundle, options, discounts } = params;
186
206
  let price = Number(product.price);
207
+ const optionRows = (options == null ? void 0 : options.map((currentValue) => ({
208
+ unit: Number(currentValue.price ?? currentValue.add_price ?? 0),
209
+ num: Number(currentValue.num ?? currentValue.quantity ?? 1)
210
+ }))) ?? [];
187
211
  if (discounts == null ? void 0 : discounts.length) {
188
212
  discounts.forEach((currentValue) => {
189
213
  var _a;
190
- price = (0, import_utils2.getDiscountAmount)({
191
- amount: currentValue.amount,
192
- tag: currentValue.type,
193
- par_value: currentValue.discount.percent,
194
- metadata: {
195
- discount_card_type: (_a = currentValue == null ? void 0 : currentValue.discount) == null ? void 0 : _a.discount_card_type
214
+ const payload = toDiscountPayload(currentValue);
215
+ price = (0, import_utils2.getDiscountAmount)(payload, price, price);
216
+ if (((_a = currentValue == null ? void 0 : currentValue.config) == null ? void 0 : _a.deductOptionPrice) && optionRows.length) {
217
+ for (let i = 0; i < optionRows.length; i++) {
218
+ const row = optionRows[i];
219
+ optionRows[i] = {
220
+ ...row,
221
+ unit: (0, import_utils2.getDiscountAmount)(payload, row.unit, row.unit)
222
+ };
196
223
  }
197
- }, price, price);
224
+ }
198
225
  });
199
226
  }
200
227
  if (bundle == null ? void 0 : bundle.length) {
@@ -202,10 +229,11 @@ var getProductTotalPrice = (params) => {
202
229
  return accumulator + Number(currentValue.price) * Number(currentValue.num);
203
230
  }, price);
204
231
  }
205
- if (options == null ? void 0 : options.length) {
206
- price = options.reduce((accumulator, currentValue) => {
207
- return accumulator + Number(currentValue.price) * Number(currentValue.num);
208
- }, price);
232
+ if (optionRows.length) {
233
+ price = optionRows.reduce(
234
+ (accumulator, row) => accumulator + row.unit * row.num,
235
+ price
236
+ );
209
237
  }
210
238
  return Math.max(0, price);
211
239
  };
@@ -313,7 +341,6 @@ var formatBundleToOrigin = (bundle) => {
313
341
  option: formatOptionsToOrigin(getBundleValueByKey("option")),
314
342
  discount_list: d.discount_list,
315
343
  "bundle_selling_price": d == null ? void 0 : d.price,
316
- // "custom_price": d?.price,
317
344
  metadata: {
318
345
  custom_product_bundle_map_id: d._id,
319
346
  product_discount_difference
@@ -17,18 +17,14 @@ export declare class DiscountModule extends BaseModule implements Module, Discou
17
17
  setOriginalDiscountList(originalDiscountList: Discount[]): Promise<void>;
18
18
  getOriginalDiscountList(): Discount[];
19
19
  loadPrepareConfig(params: {
20
- action?: 'create' | 'edit';
20
+ action?: 'create';
21
21
  with_good_pass: 0 | 1;
22
22
  with_discount_card: 0 | 1;
23
23
  customer_id: number;
24
24
  with_wallet_pass_holder: 0 | 1;
25
25
  request_timezone: string;
26
- order_id?: number;
27
- }): Promise<Discount[]>;
28
- batchSearch(code: string, options?: {
29
- customerId?: number;
30
- orderId?: number;
31
26
  }): Promise<Discount[]>;
27
+ batchSearch(code: string, customerId?: number): Promise<Discount[]>;
32
28
  batchSearchByProductIds(productIds: number[]): Promise<any>;
33
29
  filterEnabledDiscountList(discountList: Discount[]): Discount[];
34
30
  private checkUsageCreditsLimit;
@@ -102,8 +102,7 @@ var DiscountModule = class extends import_BaseModule.BaseModule {
102
102
  ) || [];
103
103
  return goodPassList;
104
104
  }
105
- async batchSearch(code, options) {
106
- const { customerId, orderId } = options || {};
105
+ async batchSearch(code, customerId) {
107
106
  const result = await this.request.get(`/machinecode/batch-search`, {
108
107
  code,
109
108
  translate_flag: 1,
@@ -113,7 +112,6 @@ var DiscountModule = class extends import_BaseModule.BaseModule {
113
112
  with: ["extensionData", "customScheduleSnapshot", "holder.detail"],
114
113
  order_behavior_count: 1,
115
114
  order_behavior_count_customer_id: customerId || 1,
116
- ...orderId ? { order_behavior_count_order_id: orderId } : {},
117
115
  request_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
118
116
  });
119
117
  const resultDiscountList = this.filterEnabledDiscountList((result == null ? void 0 : result.data) || []) || [];
@@ -19,7 +19,7 @@ interface PackageSubItemUsageRules {
19
19
  type: 'universal_discount' | 'package_exclusive' | 'single_item_promo' | 'custom_usage_rules';
20
20
  rules: ("original_price" | "markup_price")[];
21
21
  package_scope?: {
22
- type: 'all_packages' | 'specific_packages' | 'product_all' | 'products';
22
+ type: 'all_packages' | 'specific_packages';
23
23
  exclude_bundle_product_ids: number[];
24
24
  include_bundle_product_ids: number[];
25
25
  filter: 0 | 1;
@@ -33,6 +33,8 @@ interface Limitedrelationproductdata {
33
33
  product_ids: number[];
34
34
  product_collection_id: number[];
35
35
  package_sub_item_usage_rules?: PackageSubItemUsageRules;
36
+ filter: 0 | 1;
37
+ exclude_product_ids: number[];
36
38
  }
37
39
  interface ApplicableProductDetails {
38
40
  amount: string;
@@ -89,6 +91,7 @@ export interface Discount {
89
91
  balance: string;
90
92
  format_title: Formattitle;
91
93
  metadata?: {
94
+ num?: number;
92
95
  discount_card_type?: 'fixed_amount' | 'percent';
93
96
  custom_product_bundle_map_id?: string;
94
97
  validity_type?: "custom_schedule_validity" | "fixed_validity";
@@ -113,6 +116,21 @@ export interface Discount {
113
116
  isSelected?: boolean;
114
117
  isAvailable?: boolean;
115
118
  isUsed?: boolean;
119
+ config?: {
120
+ isAvailable?: boolean;
121
+ /** 最大抵扣金额 */
122
+ maxDeductionAmount?: number;
123
+ /** 每单最多使用张数 */
124
+ maxUsagePerOrder?: number;
125
+ /** 是否抵扣税费与附加费 */
126
+ deductTaxAndFee?: boolean;
127
+ /** 适用粒度(多商品共用) */
128
+ allowCrossProduct?: boolean;
129
+ /** 可用商品数量上限 */
130
+ applicableProductLimit?: number;
131
+ /** 是否抵扣单规格价格 (Option Price) */
132
+ deductOptionPrice?: boolean;
133
+ };
116
134
  applicableProductIds?: number[];
117
135
  applicableProductDetails: ApplicableProductDetails[];
118
136
  appliedProductDetails: ApplicableProductDetails[];
@@ -1,26 +1,13 @@
1
1
  import { Module, PisellCore, ModuleOptions } from '../../types';
2
2
  import { BaseModule } from '../BaseModule';
3
- import { OrderModuleAPI, CommitOrderParams, SubmitScanOrderParams, ScanOrderMoreParams, CheckoutOrderParams, UpdateProductInOrderParams } from './types';
3
+ import { OrderModuleAPI, CommitOrderParams, CheckoutOrderParams } from './types';
4
4
  import { CartItem } from '../Cart/types';
5
- import { type SubmitPayloadEnhancer } from './utils';
6
- import type { ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderSummary, ScanOrderTempOrder } from '../../solution/ScanOrder/types';
7
- import type { Discount } from '../Discount/types';
8
- import { UnavailableReason } from '../Rules/types';
9
5
  export declare class OrderModule extends BaseModule implements Module, OrderModuleAPI {
10
6
  protected defaultName: string;
11
7
  protected defaultVersion: string;
12
8
  private store;
13
9
  private request;
14
10
  private logger;
15
- private window;
16
- private cacheId;
17
- private salesSummaryModuleName;
18
- private rulesHooksOverride?;
19
- /**
20
- * Populate `savedAmount` on each discount based on product-level discount details.
21
- * Only selected discounts get a non-zero value.
22
- */
23
- static populateSavedAmounts(productList: Array<Record<string, any>>, discountList: Array<Record<string, any>>): void;
24
11
  constructor(name?: string, version?: string);
25
12
  initialize(core: PisellCore, options: ModuleOptions): Promise<void>;
26
13
  /**
@@ -35,52 +22,6 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
35
22
  * 记录错误日志
36
23
  */
37
24
  private logError;
38
- private registerDiscountModules;
39
- private createDefaultRulesHooks;
40
- loadDiscountConfig(params: {
41
- customerId: number;
42
- action?: 'create';
43
- }): Promise<void>;
44
- getDiscountList(): Discount[];
45
- scanCode(code: string, customerId?: number): Promise<{
46
- isAvailable: boolean;
47
- discountList: Discount[];
48
- type: 'server' | 'clientCalc';
49
- unavailableReason?: UnavailableReason;
50
- }>;
51
- applyDiscount(): void;
52
- initTempOrder(params: {
53
- cacheId?: string;
54
- salesSummaryModuleName?: string;
55
- }): void;
56
- private getTempOrderStorageKey;
57
- private restoreTempOrderFromStorage;
58
- persistTempOrder(): void;
59
- private createDefaultTempOrderInstance;
60
- ensureTempOrder(): ScanOrderTempOrder;
61
- restoreOrder(): ScanOrderTempOrder;
62
- getTempOrder(): ScanOrderTempOrder | null;
63
- addNewOrder(): Promise<ScanOrderTempOrder>;
64
- getOrderProducts(): ScanOrderOrderProduct[];
65
- private getSalesSummary;
66
- recalculateSummary(options?: {
67
- createIfMissing?: boolean;
68
- }): Promise<ScanOrderSummary | null>;
69
- getScanOrderSummary(): Promise<ScanOrderSummary>;
70
- updateTempOrderNote(note: string): string;
71
- updateTempOrderBuzzer(buzzer: string): string;
72
- updateTempOrderContactsInfo(contactsInfo: any[]): any[];
73
- addProductToOrder(product: Partial<ScanOrderOrderProduct> & ScanOrderOrderProductIdentity): Promise<ScanOrderOrderProduct[]>;
74
- updateProductInOrder(params: UpdateProductInOrderParams): Promise<ScanOrderOrderProduct[]>;
75
- removeProductFromOrder(identity: ScanOrderOrderProductIdentity): Promise<ScanOrderOrderProduct[]>;
76
- submitTempOrder<T = any>(params?: {
77
- cacheId?: string;
78
- platform?: string;
79
- businessCode?: string;
80
- channel?: string;
81
- type?: string;
82
- enhancePayload?: SubmitPayloadEnhancer;
83
- }): Promise<T>;
84
25
  createOrder(params: CommitOrderParams['query']): {
85
26
  type: "virtual" | "appointment_booking";
86
27
  platform: string;
@@ -110,9 +51,4 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
110
51
  * @returns 后端返回的订单数据(包含订单ID等)
111
52
  */
112
53
  createOrderByCheckout(params: CheckoutOrderParams): Promise<any>;
113
- submitScanOrder<T = any>(params: SubmitScanOrderParams): Promise<T>;
114
- scanOrderMore<T = any>(params: ScanOrderMoreParams): Promise<T>;
115
- getOrderInfoByRemote(order_id: number): Promise<any>;
116
- getLastOrderInfo(): Record<string, any> | undefined;
117
54
  }
118
- export type { UpdateProductInOrderParams } from './types';