| name |
version |
description |
trigger_conditions |
| voucher-module |
1.0.0 |
代金券模块:可配置规则引擎、一次性使用、模板-规则-实例三层架构 |
| 用户询问代金券功能 |
| 需要新增规则类型 |
| 代金券与 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} |
用户等级 |
新增规则类型
# 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
然后在模板管理界面为模板添加规则记录即可生效,无需改引擎代码。
规则执行流程
- 查实例状态 (unused + 未过期)
- 加载模板启用规则 (sort_order 排序)
- 逐条执行 validator,任一失败即拒绝
- 全部通过 → 抵扣 = min(面值, 消费金额)
- 写流水 + 标记券 used
与其他模块交互
llmage (推理时使用券)
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 (账单结算联动)
# 先尝试代金券,剩余从余额扣
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
部署清单
- 执行 sql/tables.sql
- sage/app/sage.py: from voucher.init import load_voucher + load_voucher()
- sage/build.sh: 安装循环添加 voucher
- sage/wwwroot/global_menu.ui: 添加菜单项(无条件,不放 {% if %} 中)
- scripts/load_path.py 注册权限
- 重启 Sage