--- name: voucher-module version: 1.0.0 description: 代金券模块:可配置规则引擎、一次性使用、模板-规则-实例三层架构 trigger_conditions: - 用户询问代金券功能 - 需要新增规则类型 - 代金券与 llmage/accounting 集成 - 代金券表结构或 API 变更 - 创建新的代金券模板或使用代金券 --- # voucher 代金券模块 ## 架构 ``` 模板 (voucher_template) └─ 规则集 (voucher_rule) ← 可配置,增删不影响代码 └─ 实例 (voucher_instance) ← 继承模板规则,一次性使用 └─ 流水 (voucher_usage_log) ``` ## 核心原则 - **一次性使用**:代金券使用后直接作废,不找零、无余额 - **规则可配置**:新增规则类型只需写 validator 函数 + @register_rule 装饰器 - **动态执行**:使用时按模板 sort_order 顺序依次校验规则 ## 表结构 | 表 | 用途 | |---|---| | voucher_template | 模板(面值、有效期、发行量、状态) | | voucher_rule | 规则(模板ID、类型、JSON配置、启用/禁用、排序) | | voucher_instance | 实例(券码、状态 unused/used/expired、面值、有效期) | | voucher_usage_log | 流水(订单、抵扣金额、产品、操作人) | ## 内置规则类型 | rule_type | config | 说明 | |-----------|--------|------| | min_amount | {"min_value": 100} | 最低消费 | | max_amount | {"max_value": 1000} | 最高消费 | | applicable_product_type | {"product_types": ["llm","image"]} | 限定产品类型 | | applicable_product | {"products": ["gpt-4"]} | 限定特定产品 | | exclude_product | {"products": ["gpt-4"]} | 排除特定产品 | | max_usage_count | {"max_count": 1} | 最大使用次数 | | valid_period | {} | 有效期(由实例字段处理) | | user_level | {"min_level": 2} | 用户等级 | ## 新增规则类型 ```python # rules/validators.py @register_rule('new_rule_type') def check_new_rule(config, context): # config: rule_config JSON 解析后的 dict # context: {request_amount, product_type, product_name, user_level, ...} if not some_condition: return False, "不满足条件" return True, None ``` 然后在模板管理界面为模板添加规则记录即可生效,无需改引擎代码。 ## 规则执行流程 1. 查实例状态 (unused + 未过期) 2. 加载模板启用规则 (sort_order 排序) 3. 逐条执行 validator,任一失败即拒绝 4. 全部通过 → 抵扣 = min(面值, 消费金额) 5. 写流水 + 标记券 used ## 与其他模块交互 ### llmage (推理时使用券) ```python from voucher.rules.engine import apply_voucher, batch_apply_vouchers, get_available_vouchers # 查询可用 vouchers = get_available_vouchers(sor, customer_id, context={ 'product_type': 'llm', 'product_name': 'gpt-4', 'request_amount': 120 }) # 单张使用 ok, deducted, err = apply_voucher(sor, instance_id, customer_id, order_id, context) # 批量使用 result = batch_apply_vouchers(sor, customer_id, order_id, [vid1, vid2], context) # → {total_deducted, remaining, details} ``` ### accounting (账单结算联动) ```python # 先尝试代金券,剩余从余额扣 result = batch_apply_vouchers(sor, customer_id, order_id, voucher_ids, context) if result['remaining'] > 0: accounting.deduct_balance(customer_id, result['remaining'], order_id) ``` ### 客户自助查询 API(voucher 自身提供) ``` GET /voucher/api/v1/available.dspy 认证: Bearer Token 参数: product_type, product_name, request_amount (均可选) 返回: {status, data: [{id, code, face_value, valid_from, valid_to, template_name}], total} ``` ### context 字段约定 | 字段 | 来源 | 说明 | |------|------|------| | request_amount | 消费金额 | 必须 | | product_type | llm.catelog | llm/image/video/audio | | product_name | 模型名 | gpt-4, dall-e-3 等 | | user_level | 客户等级 | 数字 | | valid_from/valid_to | 实例字段 | 自动注入 | ## 外部调用 API | 函数 | 用途 | |------|------| | `apply_voucher_api(customer_id, order_id, voucher_ids, context)` | 使用代金券 | | `get_available_vouchers_api(customer_id, context)` | 内部查询可用券 | | `GET /voucher/api/v1/available.dspy` | 远端客户查询可用券(HTTP API) | | `get_registered_rule_types()` | 获取规则类型列表 | ## Pitfalls - 代金券一次性使用,不要追踪 remaining_value 或 partial 状态 - 规则 config 必须是合法 JSON 字符串存储,validators 中要 try/except json.loads - batch_apply_vouchers 按顺序尝试,remaining 归零即停 - 删除模板需级联删除规则和实例 - rule_config 中数组字段用 JSON array,不用逗号分隔字符串 ## 仓库 - 路径: ~/repos/voucher/ - 远端: git@git.opencomputing.cn:yumoqing/voucher.git - SQL: sql/tables.sql (建表 + appcodes 初始化) - RBAC: scripts/load_path.py ## 部署清单 1. 执行 sql/tables.sql 2. sage/app/sage.py: from voucher.init import load_voucher + load_voucher() 3. sage/build.sh: 安装循环添加 voucher 4. sage/wwwroot/global_menu.ui: 添加菜单项(无条件,不放 {% if %} 中) 5. scripts/load_path.py 注册权限 6. 重启 Sage