# voucher — 代金券模块 独立代金券管理模块,支持**可配置规则引擎**,一次性使用,不找零。 ## 核心架构 ``` 模板(类别) → 定义规则集 实例(代金券)→ 属于某个模板,继承规则 使用流水 → 记录每次消费抵扣 ``` ### 表结构 | 表 | 说明 | |---|---| | voucher_template | 代金券模板(面值、有效期、发行量、状态) | | voucher_rule | 规则定义(模板关联,可增删启用禁用) | | voucher_instance | 券实例(一次性使用,状态:unused/used/expired) | | voucher_usage_log | 使用流水(订单、抵扣金额、产品信息) | --- ## 可配置规则引擎 规则通过 `@register_rule` 装饰器注册到 `RULE_REGISTRY`,新增规则只需写 validator 函数,无需修改引擎代码。 ### 内置规则类型 | rule_type | 说明 | rule_config 示例 | |-----------|------|------------------| | `min_amount` | 最低消费门槛 | `{"min_value": 100}` | | `max_amount` | 最高消费限制 | `{"max_value": 1000}` | | `applicable_product_type` | 限定产品类型(llm/image/video/audio) | `{"product_types": ["llm", "image"]}` | | `applicable_product` | 限定特定产品(具体模型名) | `{"products": ["gpt-4", "claude-3"]}` | | `exclude_product` | 排除特定产品 | `{"products": ["gpt-4"]}` | | `max_usage_count` | 最大使用次数 | `{"max_count": 1}` | | `valid_period` | 有效期检查 | `{}` (由实例 valid_from/valid_to 处理) | | `user_level` | 用户等级限制 | `{"min_level": 2}` | ### 规则执行流程 1. 查询券实例状态(unused + 未过期) 2. 加载模板关联的所有启用规则(按 sort_order 排序) 3. 依次执行 validator,任一失败即拒绝 4. 全部通过 → 计算抵扣金额 = min(面值, 消费金额) 5. 记录流水 + 标记券为已使用(一次性作废) ### 新增规则步骤 ```python # rules/validators.py @register_rule('new_rule_type') def check_new_rule(config, context): # config: 从 rule_config JSON 解析 # context: 包含 request_amount, product_type, product_name, user_level 等 if not some_condition: return False, "不满足条件" return True, None ``` 然后在模板管理界面添加 `rule_type: "new_rule_type"` 的规则记录即可。 --- ## 与其他模块交互 ### llmage 模块(消费时使用代金券) ```python # llmage 的计费逻辑中调用 voucher 引擎 from voucher.rules.engine import apply_voucher, get_available_vouchers # 查询客户可用代金券 vouchers = get_available_vouchers(sor, customer_id, context={ 'product_type': 'llm', # 从 llm.catelog 获取 'product_name': 'gpt-4', # 具体模型名 'request_amount': amount, 'user_level': customer.level }) # 使用代金券抵扣 ok, deducted, err = apply_voucher(sor, instance_id, customer_id, order_id, context={ 'request_amount': amount, 'product_type': 'llm', 'product_name': 'gpt-4' }) # 批量使用多张券 from voucher.rules.engine import batch_apply_vouchers result = batch_apply_vouchers(sor, customer_id, order_id, voucher_ids, context) # result: {total_deducted: 150.0, remaining: 50.0, details: [...]} # remaining > 0 时从余额扣减 ``` ### accounting 模块(余额扣减联动) ```python # accounting 消费流程中先尝试代金券,剩余从余额扣 total_amount = calculate_consumption(customer_id, period) # Step 1: 尝试代金券抵扣 result = batch_apply_vouchers(sor, customer_id, order_id, voucher_ids, context) # Step 2: 剩余金额从余额扣减 if result['remaining'] > 0: accounting.deduct_balance(customer_id, result['remaining'], order_id) # Step 3: 记录完整账单 accounting.record_order(order_id, total_amount, voucher_deducted=result['total_deducted'], balance_deducted=result['remaining']) ``` ### 客户自助查询 API(voucher 模块提供) voucher 模块自身提供面向远端客户的查询 API,无需通过 dapi 转发。 **接口**: `GET /voucher/api/v1/available.dspy` **认证**: Bearer Token(登录后用户) **参数**: | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | product_type | string | 否 | 产品类型过滤(llm/image/video/audio) | | product_name | string | 否 | 具体产品名过滤(如 gpt-4) | | request_amount | float | 否 | 预期消费金额(用于规则预校验) | **返回**: ```json { "status": "success", "data": [ { "id": "xxx", "code": "VCH-A1B2C3D4E5F6", "face_value": 50.00, "valid_from": "2026-01-01 00:00:00", "valid_to": "2026-01-31 00:00:00", "template_name": "新用户满减券" } ], "total": 1 } ``` **调用示例**: ```bash # 查询所有可用券 curl -H "Authorization: Bearer " \ https://ai.atvoe.com/voucher/api/v1/available.dspy # 按产品类型过滤 curl -H "Authorization: Bearer " \ "https://ai.atvoe.com/voucher/api/v1/available.dspy?product_type=llm&request_amount=100" ``` ### 集成点总结 | 调用方 | 场景 | 调用方式 | |--------|------|----------| | llmage | 推理/生成时抵扣 | `apply_voucher()` 函数调用 | | accounting | 月度账单结算 | `batch_apply_vouchers()` 函数调用 | | 远端客户 | 自助查询可用券 | `GET /voucher/api/v1/available.dspy` HTTP API | | 任意模块 | 新增规则类型 | `@register_rule` + 模板管理界面 | --- ## 目录结构 ``` voucher/ ├── voucher/ # Python 包 │ ├── __init__.py │ └── init.py # 模块初始化 + ServerEnv 注册 ├── rules/ # 规则引擎(纯 Python) │ ├── registry.py # @register_rule 装饰器 │ ├── validators.py # 内置规则校验器 │ └── engine.py # 校验/使用/批量使用 ├── wwwroot/ # 前端 │ ├── index.ui # 入口页(卡片导航) │ ├── menu.json # 菜单定义 │ └── api/ # API 端点 │ ├── template/ # 模板 CRUD │ ├── rule/ # 规则 CRUD │ ├── instance/ # 实例 CRUD │ ├── usage/ # 流水 CRUD │ ├── v1/ # 客户自助查询 API │ │ └── available.dspy # 查询可用券(Bearer 认证) │ ├── apply_voucher.dspy # 使用代金券 │ ├── get_available.dspy # 内部查询可用券 │ └── rule_types.dspy # 获取规则类型列表 ├── models/ # 表定义 JSON ├── json/ # CRUD 定义 JSON ├── sql/ │ └── tables.sql # 建表 + 编码初始化 ├── scripts/ │ └── load_path.py # RBAC 权限注册 ├── pyproject.toml └── README.md ``` --- ## 部署步骤 ### 1. 代码部署 ```bash cd ~/repos/voucher && git pull cd ~/repos/sage/pkgs && ln -sf ~/repos/voucher voucher cd voucher && ~/repos/sage/py3/bin/pip install -e . ``` ### 2. 数据库建表 ```bash mysql -u root -p sage < ~/repos/voucher/sql/tables.sql ``` ### 3. Sage 集成 ```python # sage/app/sage.py from voucher.init import load_voucher # ... in init(): load_voucher() ``` ```bash # sage/build.sh 安装循环 for m in ... voucher ``` ### 4. 菜单入口 ```json // sage/wwwroot/global_menu.ui items 数组 ,{ "name": "voucher", "label": "代金券", "icon": "fa fa-ticket", "url": "{{entire_url('/voucher/index.ui')}}", "target": "app.sage_main_content" } ``` ### 5. RBAC 权限 ```bash cd ~/repos/sage && ./py3/bin/python ~/repos/voucher/scripts/load_path.py ``` ### 6. 重启 ```bash cd ~/repos/sage && ./stop.sh && ./start.sh ``` --- ## 使用示例 ### 创建模板 + 配置规则 1. 模板管理 → 新增 → 名称"新用户满减券",面值 50,有效期 30 天 2. 点击模板 → 规则配置 → 添加规则: - 规则类型: `min_amount`,配置: `{"min_value": 100}` - 规则类型: `applicable_product_type`,配置: `{"product_types": ["llm"]}` ### 发放代金券 1. 券实例管理 → 新增 → 选择模板,填写客户 ID 2. 系统自动生成券码,设置有效期 ### 消费时抵扣 ```python # llmage 推理完成后 context = {'request_amount': 120.0, 'product_type': 'llm', 'product_name': 'gpt-4'} result = batch_apply_vouchers(sor, customer_id, order_id, [vid1, vid2], context) # → 抵扣 50(满100可用),剩余 70 从余额扣 ```