front/docs/渠道代理与返佣设计方案.md
zzh 072142d7bb
All checks were successful
Build and Deploy Front / deploy (push) Successful in 6m30s
feat: 代理门户返佣预计态与客户绑定代理
运单列表/工作台/返佣四态展示,注册归因与客户表单改绑代理,侧栏与占位邮箱优化。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-30 11:07:07 +08:00

22 KiB
Raw Blame History

渠道代理与返佣设计方案

文档状态:产品 + 概念模型 + 主流程 + 表结构草案(轻量首版已收口,可开发)
编写日期: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 建设目标

  1. 获客归因:代理专属注册链接,客户注册时绑定 AgentId。
  2. 数据可见:代理仅能看名下客户及其订单(只读;不看渠道成本/应付)。
  3. 返佣结算:按规则计提返佣 明细;首版运营按清单线下打款(不做冻结入账/提现)。
  4. 身份清晰:代理是第三种业务主体(与员工、客户并列),独立登录入口。

1.3 设计原则

  1. 不走 SaaS:同一库、同一运营方;用 AgentId 做归属,不引入 Fake.MultiTenant / 按代理拆库。
  2. 代理不碰价格:查价 / 下单 / 卖价仍走现有销售产品与 PriceTierKey;不做代理加价册。
  3. 结算只做返佣:客户仍与平台钱包结算;代理只拿佣金。
  4. 注册绑定 + 下单快照:客户长期挂 AgentId;订单落库时快照 Order.AgentId,事后换绑不影响历史单。
  5. 与 C2C 邀请拆开:AgentId 与 ReferrerCustomerId 分字段、分账本,避免双发佣金。
  6. 组织树不参与:代理不挂 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 并列解析

注册时(在现有创建客户流程旁路归因)

  1. 解析 agent 码 → 查 t_agent 且状态为启用。
  2. 写入 Customer.AgentId、AgentBindTime(不写 Channel 类扩展字段)。
  3. 创建客户、RBAC 用户、价档等 与今天一致;代理不参与报价。
  4. 若同时带了 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_withdraw
  • BaseType=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、权限码)。

菜单管理(须同步)

  1. 菜单管理新建一级菜单:名称「渠道代理」,路由 /agentAdmin,类型目录/菜单。
  2. 在该一级行点「同步子菜单及按钮」→ 写入「代理管理」「代理返佣」及按钮权限。
  3. 把权限赋给运营角色后刷新即可在侧栏看到。

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 测试要点

  1. 无码注册 → 无 AgentId、无返佣。
  2. 带码注册 → 绑定正确;停用代理无法绑定。
  3. agent + inviteCode 同传 → 只走代理。
  4. 子客户下单 → 快照 = 主客户 AgentId。
  5. 改主客户 AgentId → 旧单不变。
  6. 代理 A 查不到代理 B 数据。
  7. 代理接口无应付/买价/毛利字段。
  8. 成功与失败均可出明细;同单不重复。
  9. SalesProductIds 非空且主产品未命中 → 不发佣;改规则不追溯旧明细。
  10. freight / receivable 取数与账单口径一致。
  11. AgentCode 登录门户;进不了运营端。
  12. 无提现、无自动入余额;运营可标记 paid 或仅导出打款。

12 风险与边界

风险 应对
与裂变佣金双发 注册互斥;账本分离
运营端误授代理权限 独立 loginType + 独立门户
误做成多租户 方案明确禁止拆库/租户解析
代理要改价 本方案明确拒绝;若未来需要加价,另立方案,不在本文范围
派送失败仍发佣 已确认;BaseAmount≤0 不发;已有明细不自动追
改费后金额不准 快照不重算;运营改明细

13 评审结论(含轻量收口)

# 议题 结论
1 返佣基数 业务可配运费/应收/毛利;首版只做运费/应收,毛利 P2+
2 计提触发 deliverySuccess 与 deliveryFailed 均计提
3 子客户归属 跟主客户
4 登录凭证 AgentCode + 密码
5 提现 / 余额 首版都不做;明细 + 线下打款
6 规则形态 挂在 t_agent 三字段,不建规则表
7 clawback 首版不做自动扣回

实现前仍需对齐的字段映射

  1. freight / receivable 对应 t_order_fee 的具体费用项。
  2. 状态码以 OrderStatusCodes.DeliverySuccess / DeliveryFailed 为准。
  3. 产品限制按订单 主销售产品 匹配 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 漏改 对照客户登录分支清单
只挂成功态 失败态也要挂钩