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. 记录流水 + 标记券为已使用(一次性作废)

新增规则步骤

# 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'])

客户自助查询 APIvoucher 模块提供)

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

使用示例

创建模板 + 配置规则

  1. 模板管理 → 新增 → 名称"新用户满减券",面值 50有效期 30 天
  2. 点击模板 → 规则配置 → 添加规则:
    • 规则类型: min_amount,配置: {"min_value": 100}
    • 规则类型: applicable_product_type,配置: {"product_types": ["llm"]}

发放代金券

  1. 券实例管理 → 新增 → 选择模板,填写客户 ID
  2. 系统自动生成券码,设置有效期

消费时抵扣

# 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
No description provided
Readme 62 KiB
Languages
Python 99.7%
Shell 0.3%