运单列表/工作台/返佣四态展示,注册归因与客户表单改绑代理,侧栏与占位邮箱优化。 Co-authored-by: Cursor <cursoragent@cursor.com>
22 KiB
渠道代理与返佣设计方案
文档状态:产品 + 概念模型 + 主流程 + 表结构草案(轻量首版已收口,可开发)
编写日期:2026-10-29(同日按 §14 收窄为首版默认)
关联系统:OMS 业务(docs/oms系统设计-050801.md)、RBAC(docs/rbac系统设计-060801.md)、数据权限(docs/数据权限设计.md)、客户裂变(docs/客户裂变与营销体系设计方案.md)
关联规范:docs/前端页面设计规范.md
目标读者:产品、运营、研发、测试
0 阅读指引
| 角色 | 优先阅读 |
|---|---|
| 产品 / 运营 | §1~§4、§6、§10 |
| 前端 | §5、§7、§9 |
| 后端 / DBA | §3~§8 |
| 测试 | §4、§6、§10、§11 |
分期对照(正文已按轻量默认)
| 阶段 | 内容 | 交付 |
|---|---|---|
| 首版(P0+P1 一次交付) | 开户、注册绑定、订单快照、返佣明细、运营列表、薄代理门户 | 能归属、能出应结清单、代理只读;无冻结入账、无提现、无毛利基数 |
| P2+ | 毛利基数、多行产品规则、冻结/余额、提现、自动 clawback | 账户化与精细规则 |
代理 不碰价格;结算 只做返佣明细 + 运营线下打款。详细裁剪理由见 §14。
1 背景与目标
1.1 业务背景
OMS 当前是 单运营方部署(非多租户 SaaS):客户挂 t_customer,订单挂 CustomerId,组织树只管内部员工。已有能力中与「代理」最接近的是:
| 现有能力 | 说明 | 为何不够 |
|---|---|---|
C2C 邀请(inviteCode → ReferrerCustomerId) |
客户邀客户,推荐佣金 | 受益人是客户,不是渠道代理 |
员工顾问(?advisor= → CustomerService) |
内部客服软绑定 | 不是外部渠道方,无独立结算主体 |
价档 PriceTierKey |
客户卖价分档 | 代理方案 明确不改价 |
需要单独建设 渠道代理:通过专属注册链接获客,只看名下客户与订单,按返佣结算,且 不引入 SaaS 多租户。
1.2 建设目标
- 获客归因:代理专属注册链接,客户注册时绑定
AgentId。 - 数据可见:代理仅能看名下客户及其订单(只读;不看渠道成本/应付)。
- 返佣结算:按规则计提返佣 明细;首版运营按清单线下打款(不做冻结入账/提现)。
- 身份清晰:代理是第三种业务主体(与员工、客户并列),独立登录入口。
1.3 设计原则
- 不走 SaaS:同一库、同一运营方;用
AgentId做归属,不引入Fake.MultiTenant/ 按代理拆库。 - 代理不碰价格:查价 / 下单 / 卖价仍走现有销售产品与
PriceTierKey;不做代理加价册。 - 结算只做返佣:客户仍与平台钱包结算;代理只拿佣金。
- 注册绑定 + 下单快照:客户长期挂
AgentId;订单落库时快照Order.AgentId,事后换绑不影响历史单。 - 与 C2C 邀请拆开:
AgentId与ReferrerCustomerId分字段、分账本,避免双发佣金。 - 组织树不参与:代理不挂
organization;数据范围靠AgentId,不靠 DataPerm 组织。
2 已确认业务规则
| # | 决策 | 落点 |
|---|---|---|
| 1 | 不做多租户 / 不做代理改价 | 无代理价册;无租户连接串 |
| 2 | 结算模式 = 可配置返佣 | 首版基数仅 运费 / 应收;比例 + 可选销售产品列表挂在代理上(见 §5.4);毛利为 P2+ |
| 3 | 绑定时机 = 注册 | 链接带 agent 参数;登录后不靠链接改绑 |
| 4 | 订单归属 = 快照 | Order.AgentId = 下单时 主客户 的 AgentId |
| 5 | 登录入口 = 代理门户 | 不从运营端登录;运营端只做开户与规则配置 |
| 6 | 登录凭证 = 代理编号 | 账号为 AgentCode + 密码;loginType=2 |
| 7 | RBAC 定位 | 新增 loginType=2 + 业务表 t_agent + 固定角色 Agent;权限码宜少(约 3 个) |
| 8 | 组织 | 代理不进组织树 |
| 9 | 与邀请互斥(首版) | 注册请求带 agent 时只走代理归因,不写 ReferrerCustomerId、不发 C2C 推荐佣金 |
| 10 | 可见费用 | 代理可见客户侧应收/实付与返佣金额;不可见 payable / 买价 / 毛利 |
| 11 | 换绑 | 首版不做自助换绑;运营改 主客户 AgentId(仅影响之后新单) |
| 12 | 子客户归属 | 跟主客户:快照前 ResolveMainCustomer |
| 13 | 计提触发 | 下单写 estimated(预计);deliverySuccess / deliveryFailed 锁定为 pending;取消/全额退 → void;同单按 OrderId 幂等 |
| 14 | 首版资金形态 | 只写返佣明细,不冻结、不入余额、不提现;运营按清单线下打款;错账人工改明细(P2+ 再账户化) |
3 定位:相对用户 / 角色 / 权限 / 组织
3.1 一句话
代理 = 第三种业务主体(并列于内部员工、客户)。
登录壳子用 RBAC user;业务身份在 t_agent;功能门禁用角色权限;数据范围用 AgentId。组织不参与。
3.2 三种主体对照
| 内部员工 | 客户 | 渠道代理 | |
|---|---|---|---|
loginType |
0 |
1 |
2(新增) |
RBAC user |
有 | 有(桥接) | 有(桥接) |
| 业务主表 | 无 | t_customer |
t_agent |
| 角色 | 各类内部角色 | Customer / CustomerSub_* |
固定角色 Agent |
组织 OrganizationId |
可挂 | 不挂 | 不挂 |
| 数据范围 | 组织 / DataPerm | 自己的 CustomerId |
自己的 AgentId |
| 登录入口 | 运营端 | 客户门户 / H5 | 代理门户(独立) |
| 登录账号 | 员工 Account | 手机/邮箱/客户编号 | AgentCode(代理编号) |
| 核心诉求 | 履约与运营 | 下单支付 | 获客可见 + 返佣 |
3.3 分层关系
┌─ RBAC:谁登录、能点什么功能 ─────────────────────────┐
│ user ──user_role──► role ──► role_permission / menu │
│ └── OrganizationId(仅员工) │
└────────────────────────────────────────────────────────┘
│ mapId / UserId
▼
┌─ OMS 业务身份:你是哪种人、数据归谁 ──────────────────┐
│ 员工:靠组织 / DataPerm │
│ 客户:t_customer(下单、余额) │
│ 代理:t_agent(获客归属、返佣) │
│ └── Customer.AgentId → Order.AgentId(快照) │
└────────────────────────────────────────────────────────┘
| 概念 | 管什么 | 代理怎么用 |
|---|---|---|
| 用户 User | 账号、Token、mapId |
开户时建 user,t_agent.UserId 指向它 |
| 角色 Role | 权限码集合载体 | 预置 Agent,开通时绑定 |
| 权限 Permission | 菜单 / API 门禁 | 代理门户只读与佣金相关码 |
| 组织 Organization | 内部部门树 | 代理不进;运营在后台「代理管理」菜单维护名单 |
3.4 明确不做的混用
| 错误做法 | 原因 |
|---|---|
| 给员工加「代理」角色进运营端 | 混全量数据与运营能力;返佣主体不清 |
| 用客户账号兼代理 | 与自身下单、余额、C2C 邀请搅在一起 |
| 把代理挂进组织树当「下级公司」 | 组织不是渠道容器;会逼近伪 SaaS |
4 登录入口
4.1 结论
代理不从运营端登录。
| 入口 | 受众 | 代理 |
|---|---|---|
| 运营端 / 管理后台 | 内部员工 loginType=0 |
❌ 不登录;仅被运营管理 |
| 客户门户 / H5 | 发货客户 loginType=1 |
❌ |
| 代理门户 | 渠道代理 loginType=2 |
✅ |
4.2 门户形态(实现可选,语义固定)
- 同前端工程:登录
/agent,门户/agent/customers、/agent/orders - 或子域:
agent.<域名>
登录成功后只加载代理菜单,不出现运营菜单、不出现客户下单主流程(除非后续明确要「代客下单」,首版不做)。
4.3 运营侧职责(仍用员工账号)
运营在后台完成:代理开户 / 启停、返佣三字段(基数类型 / 比例 / 可选销售产品)、人工改绑主客户 AgentId、查看 / 导出返佣明细并线下打款。
这是 「管代理」,不是代理本人会话。
5 主流程:注册绑定 → 下单 → 结算
5.1 总览
运营开通代理 → 生成注册码 / 链接
→ 客户经链接注册 → 写 Customer.AgentId
→ 客户正常查价 / 下单 / 支付(价格逻辑不变)
→ 订单快照 Order.AgentId(跟主客户)
→ 下单 → 写预计返佣(estimated)
→ 派送成功/失败 → 锁定为待结算(pending,金额重算快照)
→ 运营按明细线下打款
→(P2+)冻结入账 / 提现 / 毛利基数 / 自动 clawback
5.2 注册绑定
链接示例
- PC:
/register?agent=AG001 - H5 / 微信:同等 query;与现有
inviteCode、advisor并列解析
注册时(在现有创建客户流程旁路归因)
- 解析
agent码 → 查t_agent且状态为启用。 - 写入
Customer.AgentId、AgentBindTime(不写 Channel 类扩展字段)。 - 创建客户、RBAC 用户、价档等 与今天一致;代理不参与报价。
- 若同时带了
inviteCode:首版以agent为准,不写ReferrerCustomerId。
约束
- 只认注册时绑定;登录后带链接不改绑。
- 无码注册 →
AgentId为空。 - 已存在客户补绑:首版仅运营后台人工改。
5.3 下单快照
客户查价、下单、充值支付:业务路径不因代理而改价。
| 场景 | 归属 |
|---|---|
| 主客户已绑定代理 | 解析主客户 → 取其 AgentId 写入订单快照 |
| 子客户下单 | 跟主客户:Order.AgentId = ResolveMainCustomer(下单客户).AgentId(与营销主客户解析对齐) |
事后运营改主客户 AgentId |
仅影响新单;历史订单快照不变 |
| 主客户未绑定 | Order.AgentId 为空,不返佣 |
快照伪代码:
mainCustomer = ResolveMarketingMainCustomer(orderCustomer)
Order.AgentId = mainCustomer.AgentId // 允许为空
5.4 返佣结算(首版轻量)
触发(均计算提成)
| 订单状态 | 是否计提 |
|---|---|
deliverySuccess(派送成功) |
✅ |
deliveryFailed(派送失败) |
✅ |
| 其他状态 | ❌ |
同一订单只生成 一条 明细(幂等:按 OrderId 判重);已有明细则跳过。失败↔成功来回 不自动重算、不自动扣回,错了运营改明细。
公式
返佣金额 = 基数金额(BaseAmount) × 返佣比例(CommissionRate)
规则挂在 t_agent 上(不建独立规则表)
| 字段 | 说明 |
|---|---|
BaseType |
首版仅 freight(运费)/ receivable(应收) |
CommissionRate |
比例,如 0.0300 |
SalesProductIds |
可选;空 = 该代理全部产品都计提;非空 = 仅订单 主销售产品 命中列表才计提 |
BaseType |
含义 | 取数示意 |
|---|---|---|
freight |
运费 | 对齐 t_order_fee 约定运费项(实现时定字段) |
receivable |
应收 | 客户侧应收合计(或约定应收口径) |
grossProfit |
毛利 | 首版不做(P2+);应收 − 应付,仅服务端算 |
其他约定
- 写明细时 快照
BaseType、BaseAmount、CommissionRate、主销售产品;改代理规则不追溯旧单。 BaseAmount ≤ 0、无Order.AgentId、或产品未命中列表 → 不生成明细。- 不做 冻结天数、定时入账、自动 clawback。
明细状态(首版两个就够)
| 状态 | 含义 |
|---|---|
pending |
已计提,待运营线下结算 |
paid |
运营已标记打款(可选;也可用备注/导出勾选,不做复杂工作流) |
资金边界
- 客户:继续与平台
Balance结算(不变)。 - 代理首版:无佣金钱包、无提现;应结金额以明细为准,运营线下打款。
- P2+:再引入余额 / 冻结 / 提现 / 毛利 / 多行规则表。
5.5 代理可见范围
| 数据 | 可见 | 不可见 |
|---|---|---|
| 名下客户列表 / 基础资料 | ✅ | 可按需脱敏手机号 |
| 名下订单列表 / 轨迹 / 状态 | ✅(Order.AgentId = 我) |
他代理数据 |
| 客户侧费用(应收 / 实付) | ✅ | payable、买价、毛利 |
| 返佣明细 | ✅ | — |
| 改价、改渠道、审充值、仓操作 | ❌ | — |
列表查询 必须 服务端强制 AgentId = 当前代理。
6 与现有邀请佣金的关系
| C2C 邀请(已有) | 渠道代理(本方案) | |
|---|---|---|
| 注册参数 | inviteCode |
agent |
| 客户字段 | ReferrerCustomerId |
AgentId |
| 受益主体 | 另一个客户 | t_agent |
| 账本 | t_referral_commission_* + 客户佣金余额 |
首版仅 t_agent_commission_detail(无代理余额) |
| 价格 | 不碰 | 不碰 |
| 同时存在 | 首版互斥(有 agent 只走代理) |
同左 |
可复用:状态触发挂钩、规则参数快照、按单幂等。首版 不抄 推荐佣金的冻结入账与会员门槛。
不要 把代理塞进 ReferrerCustomerId。
7 数据模型草案
命名与审计字段遵循 OMS 惯例:
IsDeleted、CreateUserId、CreateTime、UpdateUserId、UpdateTime。
禁止 新增库级UNIQUE KEY(业务唯一性在应用层校验)。编码类字段可建普通索引。
7.1 t_agent — 代理主数据(含返佣三字段)
| 字段 | 类型 | 说明 |
|---|---|---|
Id |
INT PK | |
UserId |
INT | 对应 RBAC user.userid / JWT mapId |
AgentCode |
VARCHAR(32) | 登录账号 + 注册链接编码;应用层保证启用态唯一 |
AgentName |
VARCHAR(64) | 显示名 |
Phone / Email |
VARCHAR | 联系用(非登录主键) |
Password |
VARCHAR | 登录密码(对齐客户模式) |
Status |
枚举 | 启用 / 停用 |
BaseType |
VARCHAR(32) | freight / receivable(首版) |
CommissionRate |
DECIMAL | 返佣比例 |
SalesProductIds |
VARCHAR/TEXT 可空 | 可选产品 Id 列表(JSON 或逗号);空=不限产品 |
Remark |
VARCHAR |
首版不建
t_agent_commission_rule、不建FreezeDays/CommissionBalance。按产品不同比例、毛利、余额 → P2+ 再扩。
7.2 t_customer 扩展
| 字段 | 说明 |
|---|---|
AgentId |
INT 可空;绑定代理(建议写在主客户上) |
AgentBindTime |
DATETIME 可空 |
7.3 t_order 扩展
| 字段 | 说明 |
|---|---|
AgentId |
INT 可空;下单快照,返佣只认此字段 |
7.4 t_agent_commission_detail — 返佣明细
| 字段 | 说明 |
|---|---|
AgentId / OrderId / CustomerId |
归属 |
SalesProductId |
订单主销售产品(快照,可空) |
BaseType |
基数类型快照 |
BaseAmount |
计提基数(快照) |
CommissionRate |
比例(快照) |
CommissionAmount |
金额 |
Status |
pending / paid(首版) |
TriggerOrderStatus |
deliverySuccess / deliveryFailed |
PaidTime / Remark |
可选;运营标记已打款 |
7.5 P2+ 再议(首版不做)
t_agent_commission_rule(多行产品规则)CommissionBalance/ 冻结入账 /t_agent_commission_withdrawBaseType=grossProfit、自动 clawback
7.6 RBAC / 认证扩展
| 项 | 说明 |
|---|---|
OmsLoginType.Agent = 2 |
Claims loginType=2 |
角色 Code=Agent |
开通时代入 user_role |
| 权限码(宜少) | Agent.Portal、Agent.Customers.Query、Agent.Orders.Query(佣金可并进订单页则可不单列) |
| 运营权限 | Agent.Admin.Query、Agent.Admin.Create、Agent.Admin.Update、Agent.Admin.Rebind |
8 接口与模块边界(草案)
8.1 运营端(员工)
| 能力 | 建议路径前缀 |
|---|---|
| 代理 CRUD / 启停 / 比例 | /agent/admin/* |
| 客户改绑 Agent | /agent/admin/rebind |
| 返佣明细查询 / 标记已打款 | /agent/admin/commission/* |
8.2 认证
| 能力 | 说明 |
|---|---|
| 代理登录 | 扩展现有 AuthService:账号 = AgentCode + 密码,签发 loginType=2 |
| 刷新令牌 | 与现有一致,按 loginType 分支 |
8.3 代理门户
| 能力 | 建议路径前缀 |
|---|---|
| 名下客户分页 | /agent/portal/customers/* |
| 名下订单分页 / 详情(脱敏成本字段) | /agent/portal/orders/* |
| 返佣明细(可与订单同页) | /agent/portal/commission/* 或并入 orders |
8.4 注册归因改动点
- PC / H5 / 微信注册入参增加
agent(或agentCode)。 CustomerService.CreateAsync(及微信注册同源逻辑)增加AgentBinder,与MarketingReferralBinder、StaffAdvisorBinder并列。- 下单创建订单处:
ResolveMainCustomer→ 写Order.AgentId。 - 订单状态机在
deliverySuccess与deliveryFailed两处挂钩计提(幂等写明细)。
9 前端页面范围
9.1 运营端
- 代理列表 / 新建编辑 / 启停(路由
/agentAdmin/list) - 返佣明细(路由
/agentAdmin/commission) - (可选)客户详情展示所属代理、改绑入口
遵循 docs/前端页面设计规范.md(容器、工具栏、TablePro、权限码)。
菜单管理(须同步)
- 菜单管理新建一级菜单:名称「渠道代理」,路由
/agentAdmin,类型目录/菜单。 - 在该一级行点「同步子菜单及按钮」→ 写入「代理管理」「代理返佣」及按钮权限。
- 把权限赋给运营角色后刷新即可在侧栏看到。
9.2 代理门户(首版三页即可)
- 登录页
/agent(AgentCode+ 密码) - 客户列表
/agent/customers(只读) - 订单列表 + 返佣明细
/agent/orders
样式可复用中后台组件,路由与布局与运营端隔离。
不要把代理门户页面同步进运营端菜单管理;代理端独立登录,不走后台菜单树。
9.3 注册页
- 识别
agent参数;提交注册时带回。 - 无需向客户展示复杂代理信息(可选展示「渠道推荐」文案)。
10 分期与验收
首版(一次交付)
t_agent(含BaseType/CommissionRate/SalesProductIds)+ 客户/订单AgentId- 运营开户、启停、改三字段规则、改绑主客户
- 注册链接归因;有
agent时不写 C2C 引荐 - 下单快照跟主客户;
deliverySuccess/deliveryFailed幂等写明细 - 运营返佣明细列表 / 导出 / 可选标记
paid loginType=2,AgentCode登录 + 角色Agent- 代理门户三页只读 + 接口强制
AgentId - 无 冻结、余额入账、提现、毛利基数、自动 clawback
P2+
grossProfit基数- 多行产品规则表
- 冻结 /
CommissionBalance/ 提现 - 自动 clawback
- 改绑审计强化
11 测试要点
- 无码注册 → 无
AgentId、无返佣。 - 带码注册 → 绑定正确;停用代理无法绑定。
agent+inviteCode同传 → 只走代理。- 子客户下单 → 快照 = 主客户
AgentId。 - 改主客户
AgentId→ 旧单不变。 - 代理 A 查不到代理 B 数据。
- 代理接口无应付/买价/毛利字段。
- 成功与失败均可出明细;同单不重复。
SalesProductIds非空且主产品未命中 → 不发佣;改规则不追溯旧明细。freight/receivable取数与账单口径一致。AgentCode登录门户;进不了运营端。- 无提现、无自动入余额;运营可标记
paid或仅导出打款。
12 风险与边界
| 风险 | 应对 |
|---|---|
| 与裂变佣金双发 | 注册互斥;账本分离 |
| 运营端误授代理权限 | 独立 loginType + 独立门户 |
| 误做成多租户 | 方案明确禁止拆库/租户解析 |
| 代理要改价 | 本方案明确拒绝;若未来需要加价,另立方案,不在本文范围 |
| 派送失败仍发佣 | 已确认;BaseAmount≤0 不发;已有明细不自动追 |
| 改费后金额不准 | 快照不重算;运营改明细 |
13 评审结论(含轻量收口)
| # | 议题 | 结论 |
|---|---|---|
| 1 | 返佣基数 | 业务可配运费/应收/毛利;首版只做运费/应收,毛利 P2+ |
| 2 | 计提触发 | deliverySuccess 与 deliveryFailed 均计提 |
| 3 | 子客户归属 | 跟主客户 |
| 4 | 登录凭证 | AgentCode + 密码 |
| 5 | 提现 / 余额 | 首版都不做;明细 + 线下打款 |
| 6 | 规则形态 | 挂在 t_agent 三字段,不建规则表 |
| 7 | clawback | 首版不做自动扣回 |
实现前仍需对齐的字段映射
freight/receivable对应t_order_fee的具体费用项。- 状态码以
OrderStatusCodes.DeliverySuccess/DeliveryFailed为准。 - 产品限制按订单 主销售产品 匹配
SalesProductIds。
然后出 DDL(sql/migrate_agent_module.sql)与接口明细即可开发。
14 轻量原则与坑点(已采纳为正文默认)
§0~§10 已按本节收口;此处保留备忘,避免开发时加回复杂度。
14.1 首版最薄闭环
开户(AgentCode + BaseType/Rate/产品列表)
→ 注册绑定 → 下单快照(跟主客户)
→ 派送成功/失败写一条明细
→ 运营导出线下打款
→ 代理门户只读
14.2 明确推迟到 P2+
冻结入账、CommissionBalance、提现、grossProfit、多行规则表、自动 clawback。
14.3 必防坑
| 坑 | 对策 |
|---|---|
| 费用事后变更 | 明细快照;不自动重算 |
| 失败后退款 | BaseAmount≤0 不发;已发靠人工 |
| 状态来回 | 按 OrderId 幂等 |
| 子客户无 AgentId | 必须 ResolveMainCustomer |
| C2C 双发 | 有 agent 只走代理 |
| 门户串权 | 查询强制 AgentId |
loginType=2 漏改 |
对照客户登录分支清单 |
| 只挂成功态 | 失败态也要挂钩 |