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} |
规则执行流程
- 查询券实例状态(unused + 未过期)
- 加载模板关联的所有启用规则(按 sort_order 排序)
- 依次执行 validator,任一失败即拒绝
- 全部通过 → 计算抵扣金额 = min(面值, 消费金额)
- 记录流水 + 标记券为已使用(一次性作废)
新增规则步骤
# 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 模块(消费时使用代金券)
# 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 模块(余额扣减联动)
# 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 | 否 | 预期消费金额(用于规则预校验) |
返回:
{
"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
}
调用示例:
# 查询所有可用券
curl -H "Authorization: Bearer <token>" \
https://ai.atvoe.com/voucher/api/v1/available.dspy
# 按产品类型过滤
curl -H "Authorization: Bearer <token>" \
"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. 代码部署
cd ~/repos/voucher && git pull
cd ~/repos/sage/pkgs && ln -sf ~/repos/voucher voucher
cd voucher && ~/repos/sage/py3/bin/pip install -e .
2. 数据库建表
mysql -u root -p sage < ~/repos/voucher/sql/tables.sql
3. Sage 集成
# sage/app/sage.py
from voucher.init import load_voucher
# ... in init():
load_voucher()
# sage/build.sh 安装循环
for m in ... voucher
4. 菜单入口
// 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 权限
cd ~/repos/sage && ./py3/bin/python ~/repos/voucher/scripts/load_path.py
6. 重启
cd ~/repos/sage && ./stop.sh && ./start.sh
使用示例
创建模板 + 配置规则
- 模板管理 → 新增 → 名称"新用户满减券",面值 50,有效期 30 天
- 点击模板 → 规则配置 → 添加规则:
- 规则类型:
min_amount,配置:{"min_value": 100} - 规则类型:
applicable_product_type,配置:{"product_types": ["llm"]}
- 规则类型:
发放代金券
- 券实例管理 → 新增 → 选择模板,填写客户 ID
- 系统自动生成券码,设置有效期
消费时抵扣
# 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 从余额扣
Description
Languages
Python
99.7%
Shell
0.3%