ai-engineering-init 1.14.3 → 1.16.0

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 (54) hide show
  1. package/.claude/hooks/skill-forced-eval.js +1 -0
  2. package/.claude/skills/leniu-marketing-scenario/SKILL.md +448 -0
  3. package/.claude/skills/leniu-marketing-scenario/references/pay-meal-rules.md +197 -0
  4. package/.claude/skills/leniu-marketing-scenario/references/price-rules.md +286 -0
  5. package/.claude/skills/leniu-marketing-scenario/references/recharge-rules.md +188 -0
  6. package/.codex/skills/leniu-marketing-scenario/SKILL.md +448 -0
  7. package/.codex/skills/leniu-marketing-scenario/references/pay-meal-rules.md +197 -0
  8. package/.codex/skills/leniu-marketing-scenario/references/price-rules.md +286 -0
  9. package/.codex/skills/leniu-marketing-scenario/references/recharge-rules.md +188 -0
  10. package/.cursor/hooks/cursor-skill-eval.js +5 -6
  11. package/.cursor/rules/skill-activation.mdc +1 -2
  12. package/.cursor/skills/leniu-marketing-scenario/SKILL.md +448 -0
  13. package/.cursor/skills/leniu-marketing-scenario/references/pay-meal-rules.md +197 -0
  14. package/.cursor/skills/leniu-marketing-scenario/references/price-rules.md +286 -0
  15. package/.cursor/skills/leniu-marketing-scenario/references/recharge-rules.md +188 -0
  16. package/AGENTS.md +1 -0
  17. package/bin/index.js +445 -121
  18. package/package.json +1 -1
  19. package/.claude/skills/leniu-java-amount-handling/SKILL.md +0 -461
  20. package/.claude/skills/leniu-java-export/SKILL.md +0 -570
  21. package/.claude/skills/leniu-java-report-query-param/SKILL.md +0 -291
  22. package/.claude/skills/leniu-java-total-line/SKILL.md +0 -196
  23. package/.claude/skills/leniu-marketing-price-rule-customizer/SKILL.md +0 -301
  24. package/.claude/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +0 -285
  25. package/.claude/skills/leniu-mealtime/SKILL.md +0 -215
  26. package/.claude/skills/leniu-report-customization/SKILL.md +0 -415
  27. package/.claude/skills/leniu-report-customization/references/table-fields.md +0 -93
  28. package/.claude/skills/leniu-report-standard-customization/SKILL.md +0 -391
  29. package/.claude/skills/leniu-report-standard-customization/references/analysis-module.md +0 -64
  30. package/.claude/skills/leniu-report-standard-customization/references/table-fields.md +0 -113
  31. package/.codex/skills/leniu-java-amount-handling/SKILL.md +0 -461
  32. package/.codex/skills/leniu-java-export/SKILL.md +0 -570
  33. package/.codex/skills/leniu-java-report-query-param/SKILL.md +0 -291
  34. package/.codex/skills/leniu-java-total-line/SKILL.md +0 -196
  35. package/.codex/skills/leniu-marketing-price-rule-customizer/SKILL.md +0 -301
  36. package/.codex/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +0 -285
  37. package/.codex/skills/leniu-mealtime/SKILL.md +0 -215
  38. package/.codex/skills/leniu-report-customization/SKILL.md +0 -415
  39. package/.codex/skills/leniu-report-customization/references/table-fields.md +0 -93
  40. package/.codex/skills/leniu-report-standard-customization/SKILL.md +0 -391
  41. package/.codex/skills/leniu-report-standard-customization/references/analysis-module.md +0 -64
  42. package/.codex/skills/leniu-report-standard-customization/references/table-fields.md +0 -113
  43. package/.cursor/skills/leniu-java-amount-handling/SKILL.md +0 -461
  44. package/.cursor/skills/leniu-java-export/SKILL.md +0 -570
  45. package/.cursor/skills/leniu-java-report-query-param/SKILL.md +0 -291
  46. package/.cursor/skills/leniu-java-total-line/SKILL.md +0 -196
  47. package/.cursor/skills/leniu-marketing-price-rule-customizer/SKILL.md +0 -301
  48. package/.cursor/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +0 -285
  49. package/.cursor/skills/leniu-mealtime/SKILL.md +0 -215
  50. package/.cursor/skills/leniu-report-customization/SKILL.md +0 -415
  51. package/.cursor/skills/leniu-report-customization/references/table-fields.md +0 -93
  52. package/.cursor/skills/leniu-report-standard-customization/SKILL.md +0 -391
  53. package/.cursor/skills/leniu-report-standard-customization/references/analysis-module.md +0 -64
  54. package/.cursor/skills/leniu-report-standard-customization/references/table-fields.md +0 -113
@@ -116,6 +116,7 @@ const instructions = `## 强制技能激活流程(必须执行)
116
116
  - update-status: 更新状态/状态变更
117
117
  - skill-creator: 创建技能模板/技能脚手架/skill scaffold
118
118
  - leniu-report-scenario: 报表/报表开发/报表查询/报表导出/合计行/totalLine/汇总报表/定制报表/report_order_info/金额处理/分转元/餐次/mealtime/ReportBaseTotalVO/CustomNumberConverter
119
+ - leniu-marketing-scenario: 营销/营销规则/消费规则/计价规则/充值规则/扣款规则/就餐规则/折扣/满减/限额/限次/补贴/赠送/满赠/管理费/MarketApi/RulePriceHandler/RuleRechargeHandler/RulePayHandler/MarketRule/规则定制
119
120
 
120
121
  ### 步骤 2 - 激活(逐个调用,等待每个完成)
121
122
 
@@ -0,0 +1,448 @@
1
+ ---
2
+ name: leniu-marketing-scenario
3
+ description: |
4
+ leniu-tengyun-core 营销规则开发场景化技能。统一覆盖四大规则模块(就餐/计价/扣款/充值)的新增、定制、调试全场景。
5
+ 当用户提到任何与营销规则、消费规则、计费规则、优惠折扣、限额限次、充值赠送等相关的开发需求时,
6
+ 都应使用此技能——即使用户没有明确说"营销",只要涉及规则 Handler、规则定制、@Primary 覆盖,就属于本技能的范畴。
7
+
8
+ 触发场景:
9
+ - 新增营销规则类型(计价/充值/扣款/就餐)
10
+ - 定制现有规则逻辑(@Primary 模式重写 Handler)
11
+ - 扩展规则 DTO 字段(向后兼容)
12
+ - 营销规则 CRUD(Controller/Service/Mapper)
13
+ - 调试营销规则计算逻辑(MarketApi 入口排查)
14
+ - 用户说"加个折扣规则"、"限制每日消费次数"、"充值满赠"等
15
+
16
+ 触发词:营销、营销规则、消费规则、计价规则、充值规则、扣款规则、就餐规则、折扣、满减、限额、限次、补贴、赠送、满赠、管理费、MarketApi、RulePriceHandler、RuleRechargeHandler、RulePayHandler、RuleMealHandler、RulePriceEnum、RuleRechargeEnum、MarketRule、规则定制、@Primary覆盖
17
+ ---
18
+
19
+ # leniu 营销规则开发场景化指南
20
+
21
+ > **本技能合并了 2 个营销碎片技能(price-rule-customizer、recharge-rule-customizer)的核心知识,并扩展覆盖全部四大规则模块。**
22
+ > 按需加载详细参考:
23
+ > - 计价规则全部类型详解 → 读 `references/price-rules.md`
24
+ > - 充值规则全部类型详解 → 读 `references/recharge-rules.md`
25
+ > - 扣款/就餐规则详解 → 读 `references/pay-meal-rules.md`
26
+
27
+ ---
28
+
29
+ ## 一、决策树(开发前先过一遍)
30
+
31
+ ### Q1: 涉及哪个规则模块?
32
+
33
+ | 模块 | moduleType | 说明 | Handler 接口 |
34
+ |------|-----------|------|-------------|
35
+ | **就餐规则** | 1 | 就餐时段限制、菜品类别限制 | `RuleMealHandler` |
36
+ | **计价规则** | 2 | 折扣/满减/限额/限次/补贴/菜品优惠/商品优惠 | `RulePriceHandler` |
37
+ | **扣款规则** | 3 | 扣款顺序/最低余额/消费限额 | `RulePayHandler` |
38
+ | **充值规则** | 4 | 满赠/按次赠送/限额/管理费 | `RuleRechargeHandler` |
39
+
40
+ ### Q2: 什么类型的开发任务?
41
+
42
+ | 任务 | 操作 |
43
+ |------|------|
44
+ | **新增规则类型** | 创建 DTO + Extension 接口 + Default 实现 + 注册枚举 |
45
+ | **重写规则逻辑(@Primary)** | 定制项目中创建 @Primary 实现类 |
46
+ | **扩展 DTO 字段** | 在核心包名下覆盖 DTO 类,新字段支持 null |
47
+ | **营销管理 CRUD** | MarketRuleController + MarketRuleService |
48
+ | **调试规则计算** | 从 MarketApi 入口跟踪 → Provider → Handler |
49
+
50
+ ### Q3: 是核心开发还是定制开发?
51
+
52
+ | 场景 | 代码位置 | 包名 |
53
+ |------|---------|------|
54
+ | **核心(标准版)** | `sys-canteen/.../marketing/v2/` | `net.xnzn.core.marketing.v2.*` |
55
+ | **定制(项目定制)** | 定制仓库对应目录 | `net.xnzn.yunshitang.marketing.*` |
56
+
57
+ ---
58
+
59
+ ## 二、架构总览
60
+
61
+ ### 四大规则模块 + 策略模式
62
+
63
+ ```
64
+ MarketApi(统一入口)
65
+ ├── RuleMealApi → RuleMealProvider → RuleMealHandler(策略接口)
66
+ ├── RulePriceApi → RulePriceProvider → RulePriceHandler(策略接口)
67
+ ├── RulePayApi → RulePayProvider → RulePayHandler(策略接口)
68
+ └── RuleRechargeApi→ RuleRechargeProvider→ RuleRechargeHandler(策略接口)
69
+ ```
70
+
71
+ ### 核心类职责
72
+
73
+ | 类 | 职责 |
74
+ |----|------|
75
+ | `MarketApi` | 统一入口,分布式锁、规则开关检查、路由到对应 Api |
76
+ | `RuleXxxApi` | 查找匹配规则、按分类排序执行、记录计算结果 |
77
+ | `RuleXxxProvider` | Spring 自动注入所有 Handler,按 ruleType 查找 |
78
+ | `RuleXxxHandler` | 策略接口:`handle()` + `getRuleType()` + `checkRuleInfo()` |
79
+ | `MarketRuleCustomBusiness` | 扩展点:规则计算前/后的 Hook(定制项目可 @Primary 覆盖) |
80
+ | `MarketRuleService` | 规则 CRUD、适用规则查询 |
81
+ | `MarketRuleRangeService` | 规则适用范围(人员/设备/餐次) |
82
+ | `MarketUtil` | 设备 SN 格式化、历史订单查询、时间周期计算 |
83
+ | `RuleCacheManager` | 规则缓存管理 |
84
+
85
+ ### 计价规则执行顺序
86
+
87
+ ```
88
+ 限次规则 → 优惠规则 → 限额规则 → 赠送规则
89
+ ```
90
+
91
+ ### 充值规则执行顺序
92
+
93
+ ```
94
+ 限额规则 → 赠送规则 → 管理费规则
95
+ ```
96
+
97
+ ---
98
+
99
+ ## 三、Handler 三层结构(策略模式)
100
+
101
+ 每种规则类型遵循统一的三层结构:
102
+
103
+ ```
104
+ RulePriceHandler(顶层接口)
105
+ └── PriceDiscountHandlerExtension(扩展接口,定义 getRuleType + checkRuleInfo)
106
+ └── DefaultPriceDiscountHandlerImpl(默认实现,@Service)
107
+ └── CustomPriceDiscountHandlerImpl(定制实现,@Service @Primary)
108
+ ```
109
+
110
+ ### 四大 Handler 接口签名
111
+
112
+ ```java
113
+ // 计价规则
114
+ void handle(RulePriceResultOrderDTO order, MarketRuleVO rule, List<RulePriceResultOrderDTO> orderResults);
115
+
116
+ // 充值规则
117
+ void handle(RuleRechargeResultDTO resultDTO, MarketRuleVO ruleInfo);
118
+
119
+ // 扣款规则
120
+ void handle(RulePayComputeDTO computeDTO, MarketRuleVO rule, RulePayResultDTO result);
121
+
122
+ // 就餐规则
123
+ void handle(CustPayVO custPayVO, MarketRuleVO rule);
124
+ ```
125
+
126
+ ---
127
+
128
+ ## 四、规则类型速查
129
+
130
+ ### 计价规则 RulePriceEnum(18 种)
131
+
132
+ | 分类 | 枚举 | key | 说明 |
133
+ |------|------|-----|------|
134
+ | **优惠** | RULE_DISCOUNT | 1 | 打折(按次数梯度) |
135
+ | | RULE_REDUCTION_TOTAL | 2 | 累计减免 |
136
+ | | RULE_REDUCTION_FIXED | 4 | 固定减免(按次数梯度) |
137
+ | | RULE_DEDUCTION_RATIO | 5 | 比例扣费 |
138
+ | | RULE_DEDUCTION_FIXED | 6 | 固定扣费(按次数梯度) |
139
+ | | RULE_DEDUCTION_FULL | 7 | 满减满折 |
140
+ | | RULE_ADD_AMOUNT | 9 | 额外扣费 |
141
+ | **赠送** | RULE_SUBSIDY_FIXED | 3 | 固定补贴 |
142
+ | | RULE_SUM_GIVE | 8 | 满额赠送(累计门槛) |
143
+ | **限次** | RULE_LIMIT_MAX_COUNT | 51 | 上限次数 |
144
+ | | RULE_DISH_LIMIT | 201 | 菜品限购 |
145
+ | | RULE_GOODS_LIMIT | 301 | 商品限购 |
146
+ | **限额** | RULE_LIMIT_MAX_AMOUNT | 101 | 单笔上限金额 |
147
+ | | RULE_LIMIT_SUM_AMOUNT | 102 | 累计上限金额 |
148
+ | **菜品** | RULE_DISH_DISCOUNT | 151 | 菜品打折 |
149
+ | | RULE_DISH_DISCOUNT_LIMIT | 152 | 菜品打折限购 |
150
+ | | RULE_DISH_PACKAGE | 153 | 套餐优惠 |
151
+ | **商品** | RULE_GOODS_DISCOUNT | 251 | 商品打折 |
152
+ | | RULE_GOODS_DISCOUNT_LIMIT | 252 | 商品打折限购 |
153
+
154
+ ### 充值规则 RuleRechargeEnum(5 种)
155
+
156
+ | 分类 | 枚举 | key |
157
+ |------|------|-----|
158
+ | **赠送** | RULE_FULL_GIFT | 1(满赠) |
159
+ | | RULE_TIMES_GIFT | 2(按次赠送) |
160
+ | **限额** | RULE_MAX_AMOUNT | 51(单笔上限) |
161
+ | | RULE_SUM_AMOUNT | 52(累计上限) |
162
+ | **费用** | RULE_MANAGE_COST | 101(管理费) |
163
+
164
+ ### 扣款规则 RulePayEnum(3 种)
165
+
166
+ | 枚举 | key | 说明 |
167
+ |------|-----|------|
168
+ | RULE_PAY_SEQUENCE | 1 | 扣款顺序 |
169
+ | RULE_PAY_MIN_BALANCE | 2 | 钱包最低余额 |
170
+ | RULE_PAY_LIMIT_BALANCE | 3 | 钱包消费限额 |
171
+
172
+ ### 就餐规则 RuleMealEnum(2 种)
173
+
174
+ | 枚举 | key | 说明 |
175
+ |------|-----|------|
176
+ | RULE_TIME_LIMIT | 1 | 就餐时段限制 |
177
+ | RULE_DISH_LIMIT | 2 | 菜品类别限制 |
178
+
179
+ ---
180
+
181
+ ## 五、新增规则模板
182
+
183
+ 以计价规则为例(充值/扣款/就餐同理,替换接口和 DTO):
184
+
185
+ ### 1. 创建 DTO
186
+
187
+ ```java
188
+ // 位置: net.xnzn.core.marketing.v2.rule.price.handler.[ruletype].dto
189
+ @Data
190
+ @ApiModel("计价规则详情-[规则名称]")
191
+ public class Price[RuleType]DTO {
192
+ @ApiModelProperty("[字段说明]")
193
+ private [Type] fieldName;
194
+
195
+ @Override
196
+ public String toString() {
197
+ return "fieldName=" + fieldName;
198
+ }
199
+ }
200
+ ```
201
+
202
+ ### 2. 创建扩展接口
203
+
204
+ ```java
205
+ // 位置: net.xnzn.core.marketing.v2.rule.price.handler.[ruletype].extension
206
+ public interface Price[RuleType]HandlerExtension extends RulePriceHandler {
207
+ @Override
208
+ default Integer getRuleType() {
209
+ return RulePriceEnum.[RULE_TYPE].getKey();
210
+ }
211
+
212
+ @Override
213
+ default String checkRuleInfo(String ruleInfo) {
214
+ Price[RuleType]DTO rule = JSON.parseObject(ruleInfo, Price[RuleType]DTO.class);
215
+ return rule.toString();
216
+ }
217
+ }
218
+ ```
219
+
220
+ ### 3. 创建默认实现
221
+
222
+ ```java
223
+ // 位置: net.xnzn.core.marketing.v2.rule.price.handler.[ruletype].extension.impl
224
+ @Slf4j
225
+ @Service
226
+ public class DefaultPrice[RuleType]HandlerImpl implements Price[RuleType]HandlerExtension {
227
+
228
+ @Autowired
229
+ private MarketRuleRangeService rangeService;
230
+
231
+ @Override
232
+ public void handle(RulePriceResultOrderDTO order, MarketRuleVO rule,
233
+ List<RulePriceResultOrderDTO> orderResults) {
234
+ // 1. 解析规则配置
235
+ Price[RuleType]DTO ruleInfo = JSON.parseObject(rule.getRuleInfo(), Price[RuleType]DTO.class);
236
+ // 2. 查询规则适用范围
237
+ List<MarketRuleRange> rangeList = rangeService.listRuleRangeLatest(rule.getRuleId());
238
+ // 3. 实现计算逻辑
239
+ // ...
240
+ // 4. 更新订单金额
241
+ order.setDiscountsAmount(order.getDiscountsAmount().add(discountAmount));
242
+ }
243
+ }
244
+ ```
245
+
246
+ ### 4. 注册枚举
247
+
248
+ ```java
249
+ // 在 RulePriceEnum 中添加
250
+ RULE_[TYPE](key, "{market_rule_price_[type]}", "描述"),
251
+ ```
252
+
253
+ ---
254
+
255
+ ## 六、定制规则模板(@Primary 模式)
256
+
257
+ ```java
258
+ // 位置: net.xnzn.yunshitang.marketing.handler(定制项目包名)
259
+ @Slf4j
260
+ @Service
261
+ @Primary
262
+ public class Custom[RuleType]HandlerImpl extends Default[RuleType]HandlerImpl
263
+ implements [RuleType]HandlerExtension {
264
+
265
+ @Override
266
+ public void handle(...) {
267
+ // 解析规则(可能包含扩展 DTO 字段)
268
+ [RuleType]DTO ruleInfo = JSON.parseObject(rule.getRuleInfo(), [RuleType]DTO.class);
269
+
270
+ // 扩展字段向后兼容:null 时保持原行为
271
+ if (CollUtil.isNotEmpty(ruleInfo.getNewField())) {
272
+ // 定制逻辑
273
+ }
274
+
275
+ // 可选:调用父类逻辑
276
+ // super.handle(...);
277
+ }
278
+ }
279
+ ```
280
+
281
+ ### 扩展 DTO 字段
282
+
283
+ ```java
284
+ // 在核心包名下覆盖 DTO(不是定制包名!)
285
+ // 位置: net.xnzn.core.marketing.v2.rule.price.handler.[ruletype].dto
286
+ @Data
287
+ public class Price[RuleType]DTO {
288
+ // 原有字段...
289
+ private BigDecimal limitAmount;
290
+
291
+ // 扩展字段(必须支持 null)
292
+ @ApiModelProperty("新增字段(null=默认行为)")
293
+ private List<Integer> newField;
294
+ }
295
+ ```
296
+
297
+ ---
298
+
299
+ ## 七、MarketApi 入口速查
300
+
301
+ ```java
302
+ @Autowired
303
+ private MarketApi marketApi;
304
+
305
+ // 计价规则计算(带分布式锁)
306
+ RulePriceResultDTO result = marketApi.rulePriceCompute(rulePriceDTO);
307
+
308
+ // 充值规则计算(带分布式锁)
309
+ RuleRechargeResultDTO result = marketApi.ruleRechargeCompute(computeDTO);
310
+
311
+ // 扣款规则计算
312
+ RulePayResultDTO result = marketApi.rulePayCompute(computeDTO);
313
+
314
+ // 就餐规则计算
315
+ marketApi.ruleMealCompute(rulePriceDTO);
316
+
317
+ // 取消订单清除优惠记录
318
+ marketApi.disableMarketRecord(orderIds);
319
+ ```
320
+
321
+ ### 规则开关机制
322
+
323
+ 每个规则模块通过 `AllocGroupMetadataApi` 控制开关:
324
+ - `MetadataFiledConstants.RULE_MEAL` → 就餐规则
325
+ - `MetadataFiledConstants.RULE_PRICE` → 计价规则
326
+ - `MetadataFiledConstants.RULE_PAY` → 扣款规则
327
+ - `MetadataFiledConstants.RULE_RECHARGE` → 充值规则
328
+
329
+ ---
330
+
331
+ ## 八、关键数据模型
332
+
333
+ ### MarketRule(规则基本信息)
334
+
335
+ | 字段 | 类型 | 说明 |
336
+ |------|------|------|
337
+ | ruleId | Long | 规则ID(雪花ID) |
338
+ | ruleName | String | 规则名称 |
339
+ | sceneType | Integer | 场景类型 |
340
+ | moduleType | Integer | 模块类型(1就餐/2计价/3扣款/4充值) |
341
+ | ruleType | Integer | 规则类型(对应枚举 key) |
342
+ | effectTimeType | Integer | 生效时间类型(1限制/2不限) |
343
+ | effectBeginTime | LocalDate | 生效开始时间 |
344
+ | effectEndTime | LocalDate | 生效结束时间 |
345
+ | effectTimeValue | String | 时间段(逗号分隔) |
346
+ | effectPeriod | Integer | 周期(1每天/2每周/3每月/4日期) |
347
+ | ruleInfo | String | **规则配置JSON**(对应 DTO) |
348
+ | sort | Integer | 优先级 |
349
+ | version | Integer | 版本号 |
350
+
351
+ ### MarketRuleRange(规则适用范围)
352
+
353
+ 关联人员组、食堂、档口、设备、餐次等维度。
354
+
355
+ ### MarketRuleRecord(规则计算记录)
356
+
357
+ 记录每次规则计算结果,用于累计统计(限次/限额/赠送门槛等)。
358
+
359
+ ---
360
+
361
+ ## 九、常见开发场景
362
+
363
+ ### 场景 A:新增一个计价优惠规则
364
+
365
+ 1. 确定规则分类(优惠/限次/限额/赠送)
366
+ 2. 在 `RulePriceEnum` 注册枚举(选择合适的 key 范围)
367
+ 3. 创建 DTO → Extension → DefaultImpl(参考第五节模板)
368
+ 4. 读 `references/price-rules.md` 了解现有实现
369
+
370
+ ### 场景 B:定制现有规则行为
371
+
372
+ 1. 确定要定制的 Handler 和 Extension 接口
373
+ 2. 在定制项目中创建 @Primary 实现(参考第六节模板)
374
+ 3. 可选:扩展 DTO 字段
375
+
376
+ ### 场景 C:调试规则计算不生效
377
+
378
+ 1. 检查规则开关:`MetadataFiledConstants.RULE_XXX` 是否启用
379
+ 2. 检查规则匹配:`MarketRuleService.getSuitableRules()` 返回值
380
+ 3. 检查 Handler 路由:`RulePriceProvider.getMarketPriceHandler(ruleType)`
381
+ 4. 检查分布式锁:`MarketApi` 中的 RedisLock 是否超时
382
+
383
+ ### 场景 D:营销规则管理页面
384
+
385
+ Controller: `MarketRuleController` → `/api/v2/market/rule/*`
386
+ - `POST /page` — 分页查询
387
+ - `POST /detail` — 规则详情
388
+ - `POST /add` — 新增
389
+ - `POST /edit` — 修改
390
+ - `POST /remove/{ruleId}` — 删除
391
+ - `POST /change` — 启用/禁用
392
+ - `GET /enums` — 规则枚举列表
393
+
394
+ ---
395
+
396
+ ## 十、MQ 消费
397
+
398
+ | 监听器 | 职责 |
399
+ |--------|------|
400
+ | `MarketOrderMQListener` | 订单相关事件处理 |
401
+ | `MarketAccountMQListener` | 账户相关事件处理 |
402
+ | `MarketSumGiveMQListener` | 满额赠送异步处理 |
403
+
404
+ ---
405
+
406
+ ## 十一、包结构速查
407
+
408
+ ```
409
+ net.xnzn.core.marketing.v2/
410
+ ├── api/ # MarketApi(统一入口)
411
+ ├── cache/ # RuleCacheManager
412
+ ├── config/ # MQ Listeners
413
+ ├── constants/ # 通用枚举(场景/模块/设备树/生效时间/周期)
414
+ ├── controller/ # MarketRuleController
415
+ ├── custom/ # MarketRuleCustomBusiness(扩展点)
416
+ ├── dto/ # 规则编辑/记录 DTO
417
+ ├── mapper/ # Mapper + XML
418
+ ├── model/ # Entity(MarketRule/Range/Record/Ext/History)
419
+ ├── param/ # 查询参数
420
+ ├── rule/
421
+ │ ├── meal/ # 就餐规则(handler/api/constants)
422
+ │ ├── price/ # 计价规则(handler/api/constants/dto)
423
+ │ │ └── handler/
424
+ │ │ ├── discount/ # 打折(dto/extension/impl)
425
+ │ │ ├── limitmaxcount/ # 限次
426
+ │ │ └── ... # 其他 18 种规则类型
427
+ │ ├── pay/ # 扣款规则
428
+ │ └── recharge/ # 充值规则
429
+ ├── service/ # Service 层
430
+ ├── util/ # MarketUtil
431
+ └── vo/ # 返回对象
432
+ ```
433
+
434
+ ---
435
+
436
+ ## 十二、边界与延伸
437
+
438
+ 本技能覆盖营销规则开发的完整场景。以下情况请使用其他技能:
439
+
440
+ - 非营销的普通 CRUD → `leniu-crud-development`
441
+ - 报表统计(消费汇总等)→ `leniu-report-scenario`
442
+ - 定制项目代码位置规范 → `leniu-customization-location`
443
+ - MQ 消费通用规范 → `leniu-java-mq`
444
+
445
+ 本技能的 references 目录按需加载:
446
+ - 计价规则 18 种类型全部详解 → 读 `references/price-rules.md`
447
+ - 充值规则 5 种类型全部详解 → 读 `references/recharge-rules.md`
448
+ - 扣款/就餐规则详解 → 读 `references/pay-meal-rules.md`
@@ -0,0 +1,197 @@
1
+ # 扣款规则 & 就餐规则详解
2
+
3
+ ## 扣款规则(RulePayEnum)
4
+
5
+ ### 概述
6
+
7
+ 扣款规则控制消费时钱包的扣款行为:扣款顺序、最低余额保护、消费限额。
8
+
9
+ ### Handler 接口
10
+
11
+ ```java
12
+ public interface RulePayHandler {
13
+ void handle(RulePayComputeDTO computeDTO, MarketRuleVO rule, RulePayResultDTO result);
14
+ Integer getRuleType();
15
+ default void checkRuleInfo(String ruleInfo) {}
16
+ }
17
+ ```
18
+
19
+ ### 1. 扣款顺序(RULE_PAY_SEQUENCE, key=1)
20
+
21
+ 控制多钱包消费时的扣款优先级。
22
+
23
+ ```java
24
+ // DTO
25
+ public class PaySequence {
26
+ private List<Integer> walletSequence; // 钱包扣款顺序 [补贴钱包, 个人钱包]
27
+ }
28
+
29
+ // Handler 路径
30
+ rule.pay.handler.sequence.extension.impl.DefaultPaySequenceHandlerExtension
31
+
32
+ // Extension 接口
33
+ public interface PaySequenceHandlerExtension extends RulePayHandler {
34
+ @Override
35
+ default Integer getRuleType() {
36
+ return RulePayEnum.RULE_PAY_SEQUENCE.getKey();
37
+ }
38
+ }
39
+ ```
40
+
41
+ ### 2. 钱包最低余额(RULE_PAY_MIN_BALANCE, key=2)
42
+
43
+ 钱包余额不足最低额度时禁止消费。
44
+
45
+ ```java
46
+ // DTO
47
+ public class PayMinBalance {
48
+ private BigDecimal minBalance; // 最低余额(分)
49
+ }
50
+
51
+ // Handler 路径
52
+ rule.pay.handler.minbalance.extension.impl.DefaultPayMinBalanceHandlerExtension
53
+ ```
54
+
55
+ ### 3. 钱包消费限额(RULE_PAY_LIMIT_BALANCE, key=3)
56
+
57
+ 限制单次或累计从某钱包扣款的金额。
58
+
59
+ ```java
60
+ // DTO
61
+ public class PayLimitBalance {
62
+ private BigDecimal limitBalance; // 消费限额(分)
63
+ }
64
+
65
+ // Handler 路径
66
+ rule.pay.handler.limitbalance.extension.impl.DefaultPayLimitBalanceHandlerExtension
67
+ ```
68
+
69
+ ### RulePayComputeDTO 关键字段
70
+
71
+ | 字段 | 说明 |
72
+ |------|------|
73
+ | custId | 人员ID |
74
+ | orderId | 订单ID |
75
+ | orderAmount | 订单金额 |
76
+ | walletDetails | 钱包列表 |
77
+ | orderType | 订单类型 |
78
+
79
+ ### RulePayResultDTO 关键字段
80
+
81
+ | 字段 | 说明 |
82
+ |------|------|
83
+ | walletSequence | 最终扣款顺序 |
84
+ | minBalance | 最低余额限制 |
85
+ | limitBalance | 消费限额 |
86
+
87
+ ---
88
+
89
+ ## 就餐规则(RuleMealEnum)
90
+
91
+ ### 概述
92
+
93
+ 就餐规则在消费前进行校验,不通过则直接抛异常阻止消费。
94
+
95
+ ### Handler 接口
96
+
97
+ ```java
98
+ public interface RuleMealHandler {
99
+ void handle(CustPayVO custPayVO, MarketRuleVO rule);
100
+ Integer getRuleType();
101
+ default void checkRuleInfo(String ruleInfo) {}
102
+ }
103
+ ```
104
+
105
+ ### 1. 就餐时段限制(RULE_TIME_LIMIT, key=1)
106
+
107
+ 限制人员只能在特定时段就餐。
108
+
109
+ ```java
110
+ // DTO
111
+ public class MealTimeLimitDTO {
112
+ private List<String> allowedTimeRanges; // 允许时段 ["11:30~13:00", "17:00~19:00"]
113
+ }
114
+
115
+ // Handler 路径
116
+ rule.meal.handler.timelimit.extension.impl.DefaultMealTimeLimitHandlerImpl
117
+
118
+ // Extension 接口
119
+ public interface MealTimeLimitHandlerExtension extends RuleMealHandler {
120
+ @Override
121
+ default Integer getRuleType() {
122
+ return RuleMealEnum.RULE_TIME_LIMIT.getKey();
123
+ }
124
+ }
125
+ ```
126
+
127
+ ### 2. 菜品类别限制(RULE_DISH_LIMIT, key=2)
128
+
129
+ 限制人员只能消费特定类别的菜品。
130
+
131
+ ---
132
+
133
+ ## 定制模式(通用)
134
+
135
+ 扣款规则和就餐规则的定制模式与计价/充值规则完全一致:
136
+
137
+ ### 新增规则
138
+
139
+ 1. 创建 DTO → `rule.[pay|meal].handler.[ruletype].dto`
140
+ 2. 创建 Extension 接口 → `rule.[pay|meal].handler.[ruletype].extension`
141
+ 3. 创建默认实现 → `rule.[pay|meal].handler.[ruletype].extension.impl`
142
+ 4. 注册枚举 → `RulePayEnum` 或 `RuleMealEnum`
143
+
144
+ ### 重写规则(@Primary)
145
+
146
+ ```java
147
+ @Slf4j
148
+ @Service
149
+ @Primary
150
+ public class CustomPaySequenceHandlerImpl
151
+ implements PaySequenceHandlerExtension {
152
+
153
+ @Override
154
+ public void handle(RulePayComputeDTO computeDTO, MarketRuleVO rule, RulePayResultDTO result) {
155
+ // 定制逻辑
156
+ }
157
+ }
158
+ ```
159
+
160
+ ---
161
+
162
+ ## MarketRuleCustomBusiness 扩展点
163
+
164
+ 适用于计价规则的全局前/后置处理:
165
+
166
+ ```java
167
+ @Service
168
+ public class MarketRuleCustomBusiness implements CustomBusiness {
169
+
170
+ // 规则查询后的 Hook(可过滤/排序/修改规则列表)
171
+ public List<MarketRuleVO> afterGetSuitableRules(List<MarketRuleVO> suitableRules) {
172
+ return suitableRules;
173
+ }
174
+
175
+ // 规则计算前的 Hook(可按订单过滤规则)
176
+ public List<MarketRuleVO> beforeCompute(RulePriceResultOrderDTO order, List<MarketRuleVO> suitableRules) {
177
+ return suitableRules;
178
+ }
179
+ }
180
+ ```
181
+
182
+ 定制项目中通过 `@Primary` 覆盖:
183
+
184
+ ```java
185
+ @Service
186
+ @Primary
187
+ public class CustomMarketRuleCustomBusiness extends MarketRuleCustomBusiness {
188
+
189
+ @Override
190
+ public List<MarketRuleVO> beforeCompute(RulePriceResultOrderDTO order, List<MarketRuleVO> suitableRules) {
191
+ // 例如:按订单类型过滤掉不适用的规则
192
+ return suitableRules.stream()
193
+ .filter(rule -> isApplicable(rule, order))
194
+ .toList();
195
+ }
196
+ }
197
+ ```