@pisell/pisellos 0.0.519 → 0.0.521

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.
@@ -1,9 +0,0 @@
1
- // 导出评估器
2
- export { PromotionEvaluator } from "./evaluator";
3
-
4
- // 导出适配器
5
- export { PromotionAdapter } from "./adapter";
6
- export { default } from "./adapter";
7
-
8
- // 导出策略配置示例常量
9
- export { X_ITEMS_FOR_Y_PRICE_STRATEGY, BUY_X_GET_Y_FREE_STRATEGY } from "./examples";
@@ -24,6 +24,25 @@ var defaultStrategyMetadataCustom = {
24
24
  deductOptionPrice: false
25
25
  };
26
26
 
27
+ /**
28
+ * 条件 field → reasonCode 映射
29
+ * 用于将策略引擎返回的 failedField 转换为本地化文案 key
30
+ */
31
+ var FIELD_REASON_CODE_MAP = {
32
+ orderTotalAmount: 'order_total_amount_not_enough',
33
+ applicableProductTotalAmount: 'applicable_product_total_amount_not_enough',
34
+ applicableProductCount: 'applicable_product_count_not_enough'
35
+ };
36
+
37
+ /**
38
+ * 用阈值替换文案中的占位符(同时兼容 ${value} 和 {value})
39
+ */
40
+ function formatReason(template, value) {
41
+ if (!template) return template;
42
+ var replacement = value === undefined || value === null ? '' : String(value);
43
+ return template.replace(/\$\{value\}/g, replacement).replace(/\{value\}/g, replacement);
44
+ }
45
+
27
46
  /**
28
47
  * Wallet Pass 评估器
29
48
  * 用于评估哪些 voucher 可以在当前订单中使用
@@ -191,13 +210,17 @@ export var WalletPassEvaluator = /*#__PURE__*/function () {
191
210
  strategyResult: evaluationResult
192
211
  });
193
212
  } else {
194
- // 根据策略评估结果的 code 映射到 locales 中的原因
195
- var reasonCode = 'not_meet_the_required_conditions'; // 默认原因
196
-
197
- // 根据策略引擎返回的 code 映射到本地化的 reasonCode
198
- if (evaluationResult.code) {
199
- // 可以根据具体的 code 映射到不同的原因
200
- // 例如:如果是金额不足、使用次数限制等
213
+ var _evaluationResult$mat, _evaluationResult$mat2;
214
+ // 优先根据失败的 field 映射到具体的 reasonCode(更精确的失败原因)
215
+ var reasonCode = 'not_meet_the_required_conditions';
216
+ var thresholdValue = undefined;
217
+ var failedField = (_evaluationResult$mat = evaluationResult.matched) === null || _evaluationResult$mat === void 0 ? void 0 : _evaluationResult$mat.failedField;
218
+ var failedRule = (_evaluationResult$mat2 = evaluationResult.matched) === null || _evaluationResult$mat2 === void 0 || (_evaluationResult$mat2 = _evaluationResult$mat2.failedRules) === null || _evaluationResult$mat2 === void 0 ? void 0 : _evaluationResult$mat2[0];
219
+ if (failedField && FIELD_REASON_CODE_MAP[failedField]) {
220
+ reasonCode = FIELD_REASON_CODE_MAP[failedField];
221
+ thresholdValue = failedRule === null || failedRule === void 0 ? void 0 : failedRule.value;
222
+ } else if (evaluationResult.code) {
223
+ // 兜底:保留原有 code → reasonCode 映射
201
224
  var codeMapping = {
202
225
  INSUFFICIENT_AMOUNT: 'not_meet_the_required_conditions',
203
226
  USAGE_LIMIT_EXCEEDED: 'usage_limit_reached',
@@ -207,6 +230,8 @@ export var WalletPassEvaluator = /*#__PURE__*/function () {
207
230
  };
208
231
  reasonCode = codeMapping[evaluationResult.code] || 'not_meet_the_required_conditions';
209
232
  }
233
+ var rawText = this.getText(reasonCode);
234
+ var reason = thresholdValue !== undefined ? formatReason(rawText, thresholdValue) : rawText;
210
235
  results.push({
211
236
  voucher: voucher,
212
237
  isApplicable: false,
@@ -214,7 +239,7 @@ export var WalletPassEvaluator = /*#__PURE__*/function () {
214
239
  maxDeduction: 0,
215
240
  deductTaxAndFee: false,
216
241
  applicableProductIds: [],
217
- reason: this.getText(reasonCode),
242
+ reason: reason,
218
243
  reasonCode: reasonCode,
219
244
  strategyResult: evaluationResult
220
245
  });
@@ -5,7 +5,10 @@ export var locales = {
5
5
  'usage_limit_reached': '已达到使用次数上限',
6
6
  'max_passes_per_item_reached': '该商品已达到卡券使用上限',
7
7
  'not_available_for_this_channel': '当前渠道不可使用',
8
- 'not_valid_for_this_order_type': '当前订单类型不适用'
8
+ 'not_valid_for_this_order_type': '当前订单类型不适用',
9
+ 'order_total_amount_not_enough': '订单满 ${value} 才可用',
10
+ 'applicable_product_total_amount_not_enough': '适用商品满 ${value} 才可用',
11
+ 'applicable_product_count_not_enough': '至少购买 {value} 件适用商品才可用'
9
12
  },
10
13
  'en': {
11
14
  'not_meet_the_required_conditions': 'Not meet the required conditions.',
@@ -13,7 +16,10 @@ export var locales = {
13
16
  'usage_limit_reached': 'Usage limit reached.',
14
17
  'max_passes_per_item_reached': 'Max passes per item reached.',
15
18
  'not_available_for_this_channel': 'Not available for this channel.',
16
- 'not_valid_for_this_order_type': 'Not valid for this order type.'
19
+ 'not_valid_for_this_order_type': 'Not valid for this order type.',
20
+ 'order_total_amount_not_enough': 'Spend ${value} to use',
21
+ 'applicable_product_total_amount_not_enough': '${value} on eligible items',
22
+ 'applicable_product_count_not_enough': 'Buy {value} eligible items to use'
17
23
  },
18
24
  'zh-HK': {
19
25
  'not_meet_the_required_conditions': '未達使用條件',
@@ -21,6 +27,9 @@ export var locales = {
21
27
  'usage_limit_reached': '已達使用次數上限',
22
28
  'max_passes_per_item_reached': '該商品已達卡券使用上限',
23
29
  'not_available_for_this_channel': '當前渠道不可使用',
24
- 'not_valid_for_this_order_type': '當前訂單類型不適用'
30
+ 'not_valid_for_this_order_type': '當前訂單類型不適用',
31
+ 'order_total_amount_not_enough': '訂單滿 ${value} 才可用',
32
+ 'applicable_product_total_amount_not_enough': '適用商品滿 ${value} 才可用',
33
+ 'applicable_product_count_not_enough': '至少購買 {value} 件適用商品才可用'
25
34
  }
26
35
  };
@@ -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
  */
@@ -6,6 +6,8 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
6
6
  function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
7
7
  function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
8
8
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
9
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
10
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
9
11
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
10
12
  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
11
13
  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
@@ -68,6 +70,7 @@ export var StrategyEngine = /*#__PURE__*/function () {
68
70
  errors: []
69
71
  };
70
72
  try {
73
+ var _evaluationResult$fai;
71
74
  // 验证配置
72
75
  this.validateConfig(config);
73
76
  if (this.options.enableTrace) {
@@ -125,11 +128,14 @@ export var StrategyEngine = /*#__PURE__*/function () {
125
128
  applicable: applicable,
126
129
  code: applicable ? SUCCESS_CODES.SUCCESS : NOT_APPLICABLE_CODES.CONDITION_NOT_MET,
127
130
  message: applicable ? 'Strategy is applicable' : 'Conditions not met',
128
- matched: {
131
+ matched: _objectSpread({
129
132
  conditions: applicable,
130
133
  actionIds: evaluationResult.actionIds,
131
134
  details: {}
132
- },
135
+ }, applicable ? {} : {
136
+ failedField: (_evaluationResult$fai = evaluationResult.failedRules[0]) === null || _evaluationResult$fai === void 0 ? void 0 : _evaluationResult$fai.field,
137
+ failedRules: evaluationResult.failedRules
138
+ }),
133
139
  matchedActions: sortedActions,
134
140
  outputs: {},
135
141
  config: config
@@ -174,19 +180,18 @@ export var StrategyEngine = /*#__PURE__*/function () {
174
180
  *
175
181
  * @param group 条件组
176
182
  * @param context 运行时上下文
177
- * @returns 评估结果对象,包含条件是否满足和收集到的 actionIds
183
+ * @returns 评估结果对象,包含条件是否满足、收集到的 actionIds、以及失败的原子规则信息
178
184
  */
179
185
  }, {
180
186
  key: "evaluateConditionGroup",
181
187
  value: function evaluateConditionGroup(group, context) {
182
188
  var collectedActionIds = [];
183
189
 
184
- // 评估当前层的 operator 和 rules
185
- var isCurrentLayerSatisfied = this.evaluateGroupLogic(group, context);
186
-
187
- // 如果当前层条件满足
188
- if (isCurrentLayerSatisfied) {
189
- // 收集当前层的 actionIds
190
+ // 评估当前层的 operator 和 rules(同时收集失败信息)
191
+ var _this$evaluateGroupLo = this.evaluateGroupLogicDetailed(group, context),
192
+ satisfied = _this$evaluateGroupLo.satisfied,
193
+ failedRules = _this$evaluateGroupLo.failedRules;
194
+ if (satisfied) {
190
195
  collectedActionIds.push.apply(collectedActionIds, _toConsumableArray(group.actionIds));
191
196
 
192
197
  // 递归评估嵌套的 ConditionGroup,收集嵌套层的 actionIds
@@ -207,54 +212,134 @@ export var StrategyEngine = /*#__PURE__*/function () {
207
212
  }
208
213
  }
209
214
  return {
210
- satisfied: isCurrentLayerSatisfied,
211
- actionIds: collectedActionIds
215
+ satisfied: satisfied,
216
+ actionIds: collectedActionIds,
217
+ failedRules: failedRules
212
218
  };
213
219
  }
214
220
 
215
221
  /**
216
- * 评估条件组的逻辑运算
222
+ * 评估条件组的逻辑运算(带失败规则收集)
223
+ *
224
+ * 失败规则收集策略:
225
+ * - `and`:返回第一个失败的原子规则(嵌套 group 递归取其首个失败原子规则)
226
+ * - `or`:所有分支失败时,聚合每个分支的失败规则
227
+ * - `not`:被取反规则实际通过时,记录该规则
217
228
  */
218
229
  }, {
219
- key: "evaluateGroupLogic",
220
- value: function evaluateGroupLogic(group, context) {
221
- var _this = this;
230
+ key: "evaluateGroupLogicDetailed",
231
+ value: function evaluateGroupLogicDetailed(group, context) {
222
232
  var operator = group.operator,
223
233
  rules = group.rules;
224
234
  switch (operator) {
225
235
  case 'and':
226
- // 所有规则都必须满足
227
- return rules.every(function (rule) {
228
- return _this.evaluateRule(rule, context);
229
- });
236
+ {
237
+ var _iterator2 = _createForOfIteratorHelper(rules),
238
+ _step2;
239
+ try {
240
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
241
+ var rule = _step2.value;
242
+ var ruleResult = this.evaluateRuleDetailed(rule, context);
243
+ if (!ruleResult.satisfied) {
244
+ return {
245
+ satisfied: false,
246
+ failedRules: ruleResult.failedRules
247
+ };
248
+ }
249
+ }
250
+ } catch (err) {
251
+ _iterator2.e(err);
252
+ } finally {
253
+ _iterator2.f();
254
+ }
255
+ return {
256
+ satisfied: true,
257
+ failedRules: []
258
+ };
259
+ }
230
260
  case 'or':
231
- // 任一规则满足即可
232
- return rules.some(function (rule) {
233
- return _this.evaluateRule(rule, context);
234
- });
261
+ {
262
+ var aggregated = [];
263
+ var _iterator3 = _createForOfIteratorHelper(rules),
264
+ _step3;
265
+ try {
266
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
267
+ var _rule = _step3.value;
268
+ var _ruleResult = this.evaluateRuleDetailed(_rule, context);
269
+ if (_ruleResult.satisfied) {
270
+ return {
271
+ satisfied: true,
272
+ failedRules: []
273
+ };
274
+ }
275
+ aggregated.push.apply(aggregated, _toConsumableArray(_ruleResult.failedRules));
276
+ }
277
+ } catch (err) {
278
+ _iterator3.e(err);
279
+ } finally {
280
+ _iterator3.f();
281
+ }
282
+ return {
283
+ satisfied: false,
284
+ failedRules: aggregated
285
+ };
286
+ }
235
287
  case 'not':
236
- // 对第一个规则取反
237
- if (rules.length === 0) return false;
238
- return !this.evaluateRule(rules[0], context);
288
+ {
289
+ if (rules.length === 0) {
290
+ return {
291
+ satisfied: false,
292
+ failedRules: []
293
+ };
294
+ }
295
+ var _ruleResult2 = this.evaluateRuleDetailed(rules[0], context);
296
+ if (_ruleResult2.satisfied) {
297
+ // 被取反规则实际通过,导致 not 失败
298
+ var failed = this.isConditionGroup(rules[0]) ? [] : [this.buildFailedRuleInfo(rules[0], context)];
299
+ return {
300
+ satisfied: false,
301
+ failedRules: failed
302
+ };
303
+ }
304
+ return {
305
+ satisfied: true,
306
+ failedRules: []
307
+ };
308
+ }
239
309
  default:
240
310
  throw new Error("Unknown operator: ".concat(operator));
241
311
  }
242
312
  }
243
313
 
244
314
  /**
245
- * 评估单个规则
315
+ * 评估单个规则(带失败规则收集)
246
316
  */
247
317
  }, {
248
- key: "evaluateRule",
249
- value: function evaluateRule(rule, context) {
250
- // 如果是嵌套的条件组,递归评估
318
+ key: "evaluateRuleDetailed",
319
+ value: function evaluateRuleDetailed(rule, context) {
251
320
  if (this.isConditionGroup(rule)) {
252
- return this.evaluateGroupLogic(rule, context);
321
+ return this.evaluateGroupLogicDetailed(rule, context);
253
322
  }
254
-
255
- // 原子条件规则
256
323
  var conditionRule = rule;
324
+ var satisfied = this.evaluateAtomicRule(conditionRule, context);
325
+ if (satisfied) {
326
+ return {
327
+ satisfied: true,
328
+ failedRules: []
329
+ };
330
+ }
331
+ return {
332
+ satisfied: false,
333
+ failedRules: [this.buildFailedRuleInfo(conditionRule, context)]
334
+ };
335
+ }
257
336
 
337
+ /**
338
+ * 评估原子规则(不收集失败信息,仅返回布尔结果)
339
+ */
340
+ }, {
341
+ key: "evaluateAtomicRule",
342
+ value: function evaluateAtomicRule(conditionRule, context) {
258
343
  // Code 模式:使用 eval 执行
259
344
  if (conditionRule.type === 'code' && conditionRule.code) {
260
345
  return this.evaluateCodeCondition(conditionRule.code, context);
@@ -264,6 +349,21 @@ export var StrategyEngine = /*#__PURE__*/function () {
264
349
  return this.evaluateOperatorCondition(conditionRule, context);
265
350
  }
266
351
 
352
+ /**
353
+ * 构建失败规则信息
354
+ */
355
+ }, {
356
+ key: "buildFailedRuleInfo",
357
+ value: function buildFailedRuleInfo(conditionRule, context) {
358
+ var actualValue = conditionRule.field ? this.getFieldValue(conditionRule.field, context) : undefined;
359
+ return {
360
+ field: conditionRule.field,
361
+ operator: conditionRule.operator,
362
+ value: conditionRule.value,
363
+ actualValue: actualValue
364
+ };
365
+ }
366
+
267
367
  /**
268
368
  * 评估代码模式条件
269
369
  */
@@ -323,11 +423,11 @@ export var StrategyEngine = /*#__PURE__*/function () {
323
423
  // 支持点号路径,如 "order.total"
324
424
  var path = field.split('.');
325
425
  var value = context.attributes;
326
- var _iterator2 = _createForOfIteratorHelper(path),
327
- _step2;
426
+ var _iterator4 = _createForOfIteratorHelper(path),
427
+ _step4;
328
428
  try {
329
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
330
- var key = _step2.value;
429
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
430
+ var key = _step4.value;
331
431
  if (value && _typeof(value) === 'object' && key in value) {
332
432
  value = value[key];
333
433
  } else {
@@ -335,9 +435,9 @@ export var StrategyEngine = /*#__PURE__*/function () {
335
435
  }
336
436
  }
337
437
  } catch (err) {
338
- _iterator2.e(err);
438
+ _iterator4.e(err);
339
439
  } finally {
340
- _iterator2.f();
440
+ _iterator4.f();
341
441
  }
342
442
  return value;
343
443
  }
@@ -437,11 +537,11 @@ export var StrategyEngine = /*#__PURE__*/function () {
437
537
  var actionMap = new Map(actions.map(function (action) {
438
538
  return [action.id, action];
439
539
  }));
440
- var _iterator3 = _createForOfIteratorHelper(actionIds),
441
- _step3;
540
+ var _iterator5 = _createForOfIteratorHelper(actionIds),
541
+ _step5;
442
542
  try {
443
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
444
- var id = _step3.value;
543
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
544
+ var id = _step5.value;
445
545
  var action = actionMap.get(id);
446
546
  if (action) {
447
547
  matchedActions.push(action);
@@ -453,9 +553,9 @@ export var StrategyEngine = /*#__PURE__*/function () {
453
553
  }
454
554
  }
455
555
  } catch (err) {
456
- _iterator3.e(err);
556
+ _iterator5.e(err);
457
557
  } finally {
458
- _iterator3.f();
558
+ _iterator5.f();
459
559
  }
460
560
  return matchedActions;
461
561
  }
@@ -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
  * 执行轨迹
@@ -51,6 +51,10 @@
51
51
  * 匹配信息
52
52
  */
53
53
 
54
+ /**
55
+ * 失败规则信息
56
+ */
57
+
54
58
  /**
55
59
  * 执行轨迹
56
60
  */
@@ -551,7 +551,7 @@ export var WalletPassPaymentImpl = /*#__PURE__*/function () {
551
551
  order_expect_amount: params.order_expect_amount || (baseWalletParams === null || baseWalletParams === void 0 ? void 0 : baseWalletParams.order_expect_amount),
552
552
  order_product_amount: params.order_product_amount || (baseWalletParams === null || baseWalletParams === void 0 ? void 0 : baseWalletParams.order_product_amount),
553
553
  order_wait_pay_amount: params.order_wait_pay_amount || (baseWalletParams === null || baseWalletParams === void 0 ? void 0 : baseWalletParams.order_wait_pay_amount),
554
- order_behavior_count_customer_id: params.order_behavior_count_customer_id || (baseWalletParams === null || baseWalletParams === void 0 ? void 0 : baseWalletParams.order_behavior_count_customer_id),
554
+ order_behavior_count_customer_id: params.order_behavior_count_customer_id || (baseWalletParams === null || baseWalletParams === void 0 ? void 0 : baseWalletParams.order_behavior_count_customer_id) || params.customer_id || (baseWalletParams === null || baseWalletParams === void 0 ? void 0 : baseWalletParams.customer_id),
555
555
  products: params.products || (baseWalletParams === null || baseWalletParams === void 0 ? void 0 : baseWalletParams.products),
556
556
  prepare_payments: params.prepare_payments || (baseWalletParams === null || baseWalletParams === void 0 ? void 0 : baseWalletParams.prepare_payments),
557
557
  multiple: 1,
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
311
311
  date: string;
312
312
  status: string;
313
313
  week: string;
314
- weekNum: 0 | 2 | 1 | 3 | 4 | 5 | 6;
314
+ weekNum: 0 | 2 | 1 | 5 | 3 | 4 | 6;
315
315
  }[]>;
316
316
  submitTimeSlot(timeSlots: TimeSliceItem): void;
317
317
  private getScheduleDataByIds;
@@ -45,6 +45,17 @@ 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
+ function formatReason(template, value) {
54
+ if (!template)
55
+ return template;
56
+ const replacement = value === void 0 || value === null ? "" : String(value);
57
+ return template.replace(/\$\{value\}/g, replacement).replace(/\{value\}/g, replacement);
58
+ }
48
59
  var WalletPassEvaluator = class {
49
60
  constructor() {
50
61
  this.strategyConfigs = [];
@@ -101,7 +112,7 @@ var WalletPassEvaluator = class {
101
112
  * 评估可用的 vouchers
102
113
  */
103
114
  evaluate(input) {
104
- var _a, _b;
115
+ var _a, _b, _c, _d, _e;
105
116
  const { orderTotalAmount, products, vouchers, strategyConfigs } = input;
106
117
  const productIds = products.map((p) => p.product_id);
107
118
  const results = [];
@@ -176,7 +187,13 @@ var WalletPassEvaluator = class {
176
187
  });
177
188
  } else {
178
189
  let reasonCode = "not_meet_the_required_conditions";
179
- if (evaluationResult.code) {
190
+ let thresholdValue = void 0;
191
+ const failedField = (_c = evaluationResult.matched) == null ? void 0 : _c.failedField;
192
+ const failedRule = (_e = (_d = evaluationResult.matched) == null ? void 0 : _d.failedRules) == null ? void 0 : _e[0];
193
+ if (failedField && FIELD_REASON_CODE_MAP[failedField]) {
194
+ reasonCode = FIELD_REASON_CODE_MAP[failedField];
195
+ thresholdValue = failedRule == null ? void 0 : failedRule.value;
196
+ } else if (evaluationResult.code) {
180
197
  const codeMapping = {
181
198
  INSUFFICIENT_AMOUNT: "not_meet_the_required_conditions",
182
199
  USAGE_LIMIT_EXCEEDED: "usage_limit_reached",
@@ -186,6 +203,8 @@ var WalletPassEvaluator = class {
186
203
  };
187
204
  reasonCode = codeMapping[evaluationResult.code] || "not_meet_the_required_conditions";
188
205
  }
206
+ const rawText = this.getText(reasonCode);
207
+ const reason = thresholdValue !== void 0 ? formatReason(rawText, thresholdValue) : rawText;
189
208
  results.push({
190
209
  voucher,
191
210
  isApplicable: false,
@@ -193,7 +212,7 @@ var WalletPassEvaluator = class {
193
212
  maxDeduction: 0,
194
213
  deductTaxAndFee: false,
195
214
  applicableProductIds: [],
196
- reason: this.getText(reasonCode),
215
+ reason,
197
216
  reasonCode,
198
217
  strategyResult: evaluationResult
199
218
  });
@@ -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": "订单满 ${value} 才可用",
34
+ "applicable_product_total_amount_not_enough": "适用商品满 ${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 ${value} to use",
45
+ "applicable_product_total_amount_not_enough": "${value} on eligible items",
46
+ "applicable_product_count_not_enough": "Buy {value} eligible items to use"
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": "訂單滿 ${value} 才可用",
56
+ "applicable_product_total_amount_not_enough": "適用商品滿 ${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
  * 执行轨迹
@@ -389,7 +389,7 @@ var WalletPassPaymentImpl = class {
389
389
  order_expect_amount: params.order_expect_amount || (baseWalletParams == null ? void 0 : baseWalletParams.order_expect_amount),
390
390
  order_product_amount: params.order_product_amount || (baseWalletParams == null ? void 0 : baseWalletParams.order_product_amount),
391
391
  order_wait_pay_amount: params.order_wait_pay_amount || (baseWalletParams == null ? void 0 : baseWalletParams.order_wait_pay_amount),
392
- order_behavior_count_customer_id: params.order_behavior_count_customer_id || (baseWalletParams == null ? void 0 : baseWalletParams.order_behavior_count_customer_id),
392
+ order_behavior_count_customer_id: params.order_behavior_count_customer_id || (baseWalletParams == null ? void 0 : baseWalletParams.order_behavior_count_customer_id) || params.customer_id || (baseWalletParams == null ? void 0 : baseWalletParams.customer_id),
393
393
  products: params.products || (baseWalletParams == null ? void 0 : baseWalletParams.products),
394
394
  prepare_payments: params.prepare_payments || (baseWalletParams == null ? void 0 : baseWalletParams.prepare_payments),
395
395
  multiple: 1,
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
311
311
  date: string;
312
312
  status: string;
313
313
  week: string;
314
- weekNum: 0 | 2 | 1 | 3 | 4 | 5 | 6;
314
+ weekNum: 0 | 2 | 1 | 5 | 3 | 4 | 6;
315
315
  }[]>;
316
316
  submitTimeSlot(timeSlots: TimeSliceItem): void;
317
317
  private getScheduleDataByIds;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "0.0.519",
4
+ "version": "0.0.521",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",