商品管理服务,负责商品的 CRUD、批量操作、上游供应商产品同步与导入、批量定价。
| RPC | 描述 | 权限 |
| CreateProduct | 创建商品 | admin |
| ListProducts | 商品列表(分页+多维筛选) | 公开 |
| GetProduct | 获取商品详情 | 公开 |
| UpdateProduct | 更新商品信息 | admin |
| DeleteProduct | 删除商品 | admin |
| SyncProducts | 从 Provider 接口同步产品 | admin |
| BatchSetActive | 批量启用/禁用商品 | admin |
| BatchSetGroup | 批量设置商品分组 | admin |
| BatchDelete | 批量删除商品 | admin |
| ImportUpstreamProducts | 从上游导入商品 | admin |
| BatchUpdatePrice | 批量按比例更新价格 | admin |
创建一个新商品。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| name | string | 1 | 是 | 商品名称 |
| description | string | 2 | 是 | 商品描述 |
| price_per_month | string | 9 | 是 | 月度价格(字符串金额) |
| interface_id | string | 10 | 是 | 关联的 Provider 接口 ID(UUID) |
| specs | map<string,string> | 12 | 否 | 动态规格键值对 |
| group_id | string? | 13 | 否 | 商品分组 ID(UUID) |
| billing_cycles | map<string,string> | 14 | 否 | 多周期定价,如 {"monthly":"50.00","quarterly":"140.00"} |
| cost_price | string | 15 | 否 | 成本价(字符串金额) |
| 字段 | 类型 | 编号 | 描述 |
| product | ProductInfo | 1 | 创建的商品信息 |
| 错误 | 说明 |
| InvalidArgument | 参数校验失败 |
| NotFound | 指定的 interface_id 不存在 |
| PermissionDenied | 非 admin 用户 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"name":"VPS-1C2G","description":"1核2G VPS","price_per_month":"29.00","interface_id":"0192a123-...","specs":{"region":"us-west","cpu":"1","memory":"2"},"billing_cycles":{"monthly":"29.00","yearly":"290.00"}}' \
localhost:50051 rustbill.product.ProductService/CreateProduct
const resp = await api.createProduct({
name: "VPS-1C2G",
description: "1核2G VPS",
price_per_month: "29.00",
interface_id: "0192a123-...",
specs: { region: "us-west", cpu: "1", memory: "2" },
billing_cycles: { monthly: "29.00", yearly: "290.00" }
});
分页查询商品列表,支持按接口、地域、状态、关键词、分组、分类筛选。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| pagination | PageRequest | 1 | 是 | 分页参数 |
| interface_id | string? | 2 | 否 | 按 Provider 接口过滤 |
| region | string? | 3 | 否 | 按地域过滤(匹配 specs.region) |
| is_active | bool? | 4 | 否 | 按启用状态过滤 |
| search | string? | 5 | 否 | 名称关键词搜索 |
| group_id | string? | 6 | 否 | 按分组过滤 |
| category_id | string? | 8 | 否 | 按分类过滤 |
| 字段 | 类型 | 编号 | 描述 |
| products | repeated ProductInfo | 1 | 商品列表 |
| meta | PageMeta | 2 | 分页元数据 |
grpcurl -plaintext \
-d '{"pagination":{"page":1,"page_size":12},"region":"us-west","is_active":true}' \
localhost:50051 rustbill.product.ProductService/ListProducts
const resp = await api.listProducts({
pagination: { page: 1, page_size: 12 },
region: "us-west",
is_active: true
});
获取单个商品详情。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| id | string | 1 | 是 | 商品 ID(UUID) |
| 字段 | 类型 | 编号 | 描述 |
| product | ProductInfo | 1 | 商品信息 |
grpcurl -plaintext \
-d '{"id":"0192a123-4567-7890-abcd-ef0123456789"}' \
localhost:50051 rustbill.product.ProductService/GetProduct
更新商品信息。所有字段均可选,仅更新传入的字段。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| id | string | 1 | 是 | 商品 ID |
| name | string? | 2 | 否 | 商品名称 |
| description | string? | 3 | 否 | 商品描述 |
| price_per_month | string? | 4 | 否 | 月度价格 |
| is_active | bool? | 5 | 否 | 启用状态 |
| specs | map<string,string> | 6 | 否 | 动态规格(完全替换) |
| group_id | string? | 7 | 否 | 商品分组 |
| billing_cycles | map<string,string> | 8 | 否 | 多周期定价(完全替换) |
| cost_price | string? | 9 | 否 | 成本价 |
| 字段 | 类型 | 编号 | 描述 |
| product | ProductInfo | 1 | 更新后的商品信息 |
| 错误 | 说明 |
| NotFound | 商品不存在 |
| InvalidArgument | 参数校验失败 |
| PermissionDenied | 非 admin 用户 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"id":"0192a123-...","price_per_month":"35.00","is_active":false}' \
localhost:50051 rustbill.product.ProductService/UpdateProduct
删除指定商品。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| id | string | 1 | 是 | 商品 ID(UUID) |
无字段。
| 错误 | 说明 |
| NotFound | 商品不存在 |
| PermissionDenied | 非 admin 用户 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"id":"0192a123-4567-7890-abcd-ef0123456789"}' \
localhost:50051 rustbill.product.ProductService/DeleteProduct
从指定 Provider 接口同步商品列表。调用 Provider 插件的 sync_products() 函数,返回上游商品并创建本地商品记录。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| interface_id | string | 1 | 是 | Provider 接口 ID(UUID) |
| group_id | string | 2 | 否 | 同步后归入的分组 ID |
| 字段 | 类型 | 编号 | 描述 |
| synced | repeated ProductInfo | 1 | 同步后的商品列表 |
| count | uint32 | 2 | 同步数量 |
| 错误 | 说明 |
| NotFound | 接口不存在或已禁用 |
| Internal | Provider 插件执行失败 |
| PermissionDenied | 非 admin 用户 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"interface_id":"0192a123-...","group_id":"0192b456-..."}' \
localhost:50051 rustbill.product.ProductService/SyncProducts
批量启用或禁用商品。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| product_ids | repeated string | 1 | 是 | 商品 ID 列表 |
| is_active | bool | 2 | 是 | 目标启用状态 |
| 字段 | 类型 | 编号 | 描述 |
| updated_count | uint32 | 1 | 实际更新的商品数量 |
| 错误 | 说明 |
| InvalidArgument | product_ids 为空 |
| PermissionDenied | 非 admin 用户 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"product_ids":["id1","id2","id3"],"is_active":true}' \
localhost:50051 rustbill.product.ProductService/BatchSetActive
批量将商品归入指定分组。group_id 为空字符串时取消分组。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| product_ids | repeated string | 1 | 是 | 商品 ID 列表 |
| group_id | string | 2 | 是 | 目标分组 ID(空字符串=取消分组) |
| 字段 | 类型 | 编号 | 描述 |
| updated_count | uint32 | 1 | 实际更新的商品数量 |
| 错误 | 说明 |
| InvalidArgument | product_ids 为空 |
| PermissionDenied | 非 admin 用户 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"product_ids":["id1","id2"],"group_id":"0192b456-..."}' \
localhost:50051 rustbill.product.ProductService/BatchSetGroup
批量删除商品。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| product_ids | repeated string | 1 | 是 | 商品 ID 列表 |
| 字段 | 类型 | 编号 | 描述 |
| deleted_count | uint32 | 1 | 实际删除的商品数量 |
| 错误 | 说明 |
| InvalidArgument | product_ids 为空 |
| PermissionDenied | 非 admin 用户 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"product_ids":["id1","id2"]}' \
localhost:50051 rustbill.product.ProductService/BatchDelete
将上游商品批量导入本地商品表。配合 IntegrationService/SyncProducts 从上游拉取数据后批量导入。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| interface_id | string | 1 | 是 | Provider 接口 ID |
| items | repeated UpstreamProductItem | 2 | 是 | 待导入的商品列表 |
| group_id | string | 3 | 否 | 导入后归入的分组 ID |
| 字段 | 类型 | 编号 | 描述 |
| name | string | 1 | 商品名称 |
| description | string | 2 | 商品描述 |
| specs | map<string,string> | 3 | 规格键值对 |
| cost_price | string | 4 | 成本价 |
| 字段 | 类型 | 编号 | 描述 |
| imported_count | uint32 | 1 | 成功导入数量 |
| 错误 | 说明 |
| InvalidArgument | interface_id 无效或 items 为空 |
| PermissionDenied | 非 admin 用户 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"interface_id":"0192a123-...","items":[{"name":"VPS-1C1G","description":"1核1G","specs":{"cpu":"1"},"cost_price":"5.00"}],"group_id":"0192b456-..."}' \
localhost:50051 rustbill.product.ProductService/ImportUpstreamProducts
批量按加价比例更新商品售价。新售价 = 成本价 × markup_ratio。
| 字段 | 类型 | 编号 | 必填 | 描述 |
| product_ids | repeated string | 1 | 是 | 商品 ID 列表 |
| markup_ratio | string | 2 | 是 | 加价比例,如 "1.3" 表示 130%(即加价 30%) |
| 字段 | 类型 | 编号 | 描述 |
| updated_count | uint32 | 1 | 实际更新的商品数量 |
| 错误 | 说明 |
| InvalidArgument | markup_ratio 格式无效或 product_ids 为空 |
| PermissionDenied | 非 admin 用户 |
grpcurl -plaintext -H "authorization: Bearer <token>" \
-d '{"product_ids":["id1","id2"],"markup_ratio":"1.3"}' \
localhost:50051 rustbill.product.ProductService/BatchUpdatePrice
| 字段 | 类型 | 编号 | 描述 |
| id | string | 1 | 商品 UUID |
| name | string | 2 | 商品名称 |
| description | string | 3 | 商品描述 |
| price_per_month | string | 10 | 月度价格(字符串金额) |
| interface_id | string | 11 | 关联的 Provider 接口 ID |
| is_active | bool | 13 | 是否启用 |
| created_at | string | 14 | 创建时间(RFC3339) |
| updated_at | string | 15 | 更新时间(RFC3339) |
| specs | map<string,string> | 16 | 动态规格键值对 |
| group_id | string | 17 | 商品分组 ID |
| billing_cycles | map<string,string> | 18 | 多周期定价映射 |
| cost_price | string | 19 | 成本价(字符串金额) |
定义商品规格模板中的字段,由 Provider 插件提供。
| 字段 | 类型 | 编号 | 描述 |
| key | string | 1 | 字段标识符 |
| label | string | 2 | 显示标签 |
| field_type | string | 3 | 字段类型("text" / "number" / "select" / "radio") |
| required | bool | 4 | 是否必填 |
| display_order | uint32 | 5 | 显示顺序 |
| options | repeated SpecOption | 6 | 选项列表(select/radio 类型) |
| min | int64? | 7 | 最小值(number 类型) |
| max | int64? | 8 | 最大值(number 类型) |
| default_value | string? | 9 | 默认值 |
| unit | string | 10 | 单位(如 "GB", "Mbps") |
| description | string | 11 | 字段描述 |
| icon | string | 12 | 图标名称 |
| group | string | 13 | 所属分组 key |
| step | int64? | 14 | 步长(number 类型) |
| price_impact | PriceImpact | 15 | 价格影响配置 |
| 字段 | 类型 | 编号 | 描述 |
| value | string | 1 | 选项值 |
| label | string | 2 | 显示标签 |
| icon | string | 3 | 图标名称 |
| description | string | 4 | 选项描述 |
| price_modifier | string | 5 | 价格修正值 |
| disabled | bool | 6 | 是否禁用 |
| 字段 | 类型 | 编号 | 描述 |
| key | string | 1 | 分组标识符 |
| label | string | 2 | 显示标签 |
| icon | string | 3 | 图标名称 |
| display_order | uint32 | 4 | 显示顺序 |
| fields | repeated SpecField | 5 | 包含的字段列表 |
| 字段 | 类型 | 编号 | 描述 |
| mode | string | 1 | 计价模式("add" / "multiply") |
| amount | string | 2 | 价格影响金额 |
| currency | string | 3 | 货币代码 |