15 KiB
15 KiB
SMANAGE 抽象分佣引擎 — 设计文档
一、设计背景
通过对阿龙电竞平台分佣机制的完整分析,提取出 6 种核心分佣模式: 订单分佣、邀请链分佣、阶梯分佣、提现抽成、罚款分红、跨平台预结算。
这些模式都有一个共同的本质:事件 → 规则 → 分账。SMANAGE 分佣引擎将这一本质抽象为 SAAS 级通用模块,子服务只管说"发生了什么",SAAS 负责"怎么分"。
二、设计原则
| 原则 | 说明 |
|---|---|
| 事件驱动 | 子服务触发分佣事件(order_complete / member_purchase / recharge / penalty),引擎自动匹配规则计算分账 |
| 规则外置 | 分账比例、层级、公式全部存储于 CommissionRule 表,零硬编码 |
| 策略模式 | 比例/固定/阶梯/剩余 四种策略独立封装,新增分账逻辑只需添加策略类 |
| 参与方可配置 | 参与者身份和金额由 JSON 配置,适配任意业务场景 |
| 邀请链通用化 | 不管叫"管事/组长"还是"上级/上上级",都是链式分佣 |
| 幂等保护 | (TenantUUID, EventKey) 联合唯一约束,防止重复分账 |
| 快照不可变 | CommissionRecord 生成后冻结,规则变更不影响历史记录 |
| 与支付解耦 | 分佣算出"该分多少",支付模块负责"怎么打到账" |
三、架构分层
子服务(如阿龙电竞)
│
│ 订单完成 / 会员购买 / 用户充值 / 罚款缴纳
│
└──→ CommissionEngine.Dispatch(event_type, event_key, total_amount, ...)
│
├── 1. 写入 CommissionEvent(幂等检查)
├── 2. 匹配 CommissionRule(按优先级)
├── 3. 调用策略引擎计算分账
│ ├── PercentageStrategy → total × rate
│ ├── FixedStrategy → 固定金额
│ ├── TieredStrategy → 按次数/档位查表
│ └── RemainderStrategy → 剩余归平台
├── 4. 写入 CommissionRecord(不可变流水)
└── 5. 返回分账结果
四、文件清单(10 个文件)
| 层级 | 文件 | 职责 |
|---|---|---|
| 模型 | models.py |
6 张核心表:Event / Rule / RateTable / RateEntry / Record / PreSettlement |
| 策略 | strategies/engine.py |
5 种策略类 + 策略工厂 CreateStrategy() |
| 编排器 | manager.py |
CommissionEngine — Dispatch / PreSettle / 邀请链 / 费率计算 / 统计查询 |
| API | views.py |
10 个 REST 端点 |
| 序列化 | serializers.py |
12 个 Serializer |
| 路由 | urls.py |
10 个 URL 路由 |
| 配置 | apps.py |
AppConfig |
| 管理 | admin.py |
6 个 Django Admin 注册 |
五、核心数据模型
5.1 CommissionEvent — 分佣事件
子服务触发的分佣事件记录:
| 字段 | 类型 | 说明 |
|---|---|---|
| EventUUID | UUID | 主键 |
| TenantUUID | UUID | 租户 |
| EventType | CharField(32) | order_complete / member_purchase / recharge / penalty / register / custom |
| EventKey | CharField(128) | 业务唯一键(幂等保护),如订单ID |
| TotalAmount | DecimalField | 可分佣总金额 |
| SourceUserUUID | UUID | 触发者(如付费用户) |
| EventPayload | JSONField | 业务上下文(由子服务自行解析) |
| Participants | JSONField | 参与者映射 {role: user_id} |
| EventStatus | SmallIntegerField | 0=待处理 1=处理中 2=已结算 3=失败 |
唯一约束:(TenantUUID, EventKey) — 同一事件不可重复分账
5.2 CommissionRule — 分佣规则
定义"怎么分":
| 字段 | 类型 | 说明 |
|---|---|---|
| RuleUUID | UUID | 主键 |
| TenantUUID | UUID | 租户 |
| EventType | CharField(32) | 绑定的分佣事件类型 |
| RuleName | CharField(128) | 规则名称 |
| ParticipantRules | JSONField | 参与者分账规则列表 |
| RateTable | ForeignKey | 可选关联费率表 |
| MaxInviteLevel | SmallIntegerField | 邀请链最大层级(默认2级) |
| RulePriority | IntegerField | 优先级 |
ParticipantRules JSON 结构示例
[
{ "role": "worker", "type": "percentage", "value": 0.80 },
{ "role": "agent", "type": "fixed", "value": 10 },
{ "role": "leader", "type": "tiered", "tiers": { "1": 5, "2": 8, "3": 10 } },
{ "role": "platform", "type": "remainder" }
]
5.3 RateTable + RateEntry — 费率表
可复用的动态费率配置:
RateTable: { TableCode: 'dashou_order_split', TableName: '打手订单分成费率' }
├── RateEntry: { RateKey: '1', RateLabel: '平台订单打手分成', RateValue: 0.8000 }
├── RateEntry: { RateKey: '3', RateLabel: '商家订单打手分成', RateValue: 0.7000 }
├── RateEntry: { RateKey: '5', RateLabel: '打手提现抽成', RateValue: 0.0100 }
└── RateEntry: { RateKey: '6', RateLabel: '管事提现抽成', RateValue: 0.0100 }
5.4 CommissionRecord — 分佣记录(不可变)
| 字段 | 类型 | 说明 |
|---|---|---|
| RecordUUID | UUID | 主键 |
| TenantUUID | UUID | 租户 |
| Event | ForeignKey | 关联分佣事件 |
| Rule | ForeignKey | 关联分佣规则(可空,规则删除后保留快照) |
| ParticipantID | CharField(128) | 分账对象ID |
| ParticipantRole | CharField(64) | 分账角色(worker / agent / platform / ...) |
| SplitType | CharField(16) | percentage / fixed / tiered / remainder |
| Amount | DecimalField | 分账金额 |
| RuleSnapshot | JSONField | 规则快照(规则变更后保留历史) |
| TierIndex | IntegerField | 阶梯索引(多次分红时标识第几次) |
| Status | SmallIntegerField | 0=待结算 1=已结算 2=已提现 3=已取消 |
5.5 PreSettlement — 预结算
跨平台订单待确认款项:
| 字段 | 类型 | 说明 |
|---|---|---|
| EventKey | CharField(128) | 业务唯一键 |
| ExternalPlatform | CharField(64) | 外部平台标识 |
| ExternalOrderID | CharField(128) | 外部订单ID |
| ParticipantID | CharField(128) | 应分账对象 |
| Amount | DecimalField | 预分金额 |
| Status | SmallIntegerField | 0=待确认 1=已确认 2=已拒绝 |
六、策略引擎
策略模式实现,四种核心策略 + 一种扩展策略:
6.1 PercentageStrategy — 比例分账
# 配置: { role: 'worker', type: 'percentage', value: 0.80 }
amount = total_amount × 0.80
# 支持保底/封顶:
# { role: 'worker', type: 'percentage', value: 0.80, min_amount: 5, max_amount: 500 }
6.2 FixedStrategy — 固定金额
# 配置: { role: 'agent', type: 'fixed', value: 10 }
amount = 10 # 不受 total_amount 影响
# 也支持从费率表读取:
# { role: 'agent', type: 'fixed', rate_table_key: 'guanshi_fc' }
6.3 TieredStrategy — 阶梯分账
# 配置: { role: 'agent', type: 'tiered', tiers: { "1": 5, "2": 8, "3": 10 } }
# tier_index=1 → amount=5
# tier_index=2 → amount=8
# tier_index=3 → amount=10
# 支持百分比阶梯: { "1": "5%", "2": "8%" }
6.4 RemainderStrategy — 剩余归平台
# 配置: { role: 'platform', type: 'remainder' }
amount = total_amount - SUM(其他所有参与者分账)
# 自动排在最后计算,确保剩余金额正确
6.5 WithdrawalFeeStrategy — 提现手续费(扩展)
# 配置: { role: 'platform', type: 'withdrawal_fee', value: 0.01 }
fee = total_amount × 0.01
新增策略只需两步
# 1. 实现策略类
class FormulaStrategy(BaseSplitStrategy):
def Calculate(self, total_amount, tier_index=0, **context):
return total_amount * Decimal('0.5') + Decimal('10')
# 2. 注册到策略映射
STRATEGY_MAP['formula'] = FormulaStrategy
七、CommissionEngine 编排器
class CommissionEngine:
def __init__(self, tenant_uuid)
# 规则管理
def ConfigureRule(event_type, rule_name, participant_rules, ...) # 配置分佣规则
def ConfigureRateTable(table_code, table_name, entries, ...) # 配置费率表
# 核心分佣
def Dispatch(event_type, event_key, total_amount, participants, ...) # 触发分佣
def BuildInviteChainCommission(event_type, event_key, ...) # 邀请链分佣
# 预结算
def PreSettle(event_key, external_platform, external_order_id, ...) # 创建预结算
def ConfirmPreSettlement(event_key, participant_id, ...) # 确认
def RejectPreSettlement(event_key, participant_id, ...) # 拒绝
# 查询
def CalculateFee(total_amount, rate_table_code, rate_key) # 计算手续费
def QueryRecords(participant_id, event_type, status, ...) # 查询分佣记录
def TotalByParticipant(participant_id, start_date, end_date) # 统计总额
八、API 端点
# 规则管理
GET /api/commission/rule/ # 查询分佣规则列表
POST /api/commission/rule/ # 创建分佣规则
DELETE /api/commission/rule/ # 禁用分佣规则
# 费率表管理
GET /api/commission/rate/ # 查询费率表列表
POST /api/commission/rate/ # 创建费率表
# 分佣操作
POST /api/commission/dispatch/ # 触发分佣事件
POST /api/commission/dispatch/invite_chain/ # 邀请链分佣
# 查询统计
GET /api/commission/query/ # 查询分佣记录
GET /api/commission/total/<participant_id>/ # 统计某人分佣总额
POST /api/commission/fee/ # 计算手续费
# 预结算
POST /api/commission/presettle/ # 创建预结算
POST /api/commission/presettle/confirm/ # 确认预结算
# 事件查询
GET /api/commission/event/ # 查询分佣事件列表
九、子服务集成示例
9.1 订单分佣
from gvsds.apps.commission.manager import CommissionEngine
engine = CommissionEngine(tenant_uuid='al_long_001')
# 配置分佣规则
engine.ConfigureRule(
event_type='order_complete',
rule_name='平台订单打手8成',
participant_rules=[
{'role': 'worker', 'type': 'percentage', 'value': 0.80},
{'role': 'platform', 'type': 'remainder'},
],
)
# 订单完成时触发分佣
records = engine.Dispatch(
event_type='order_complete',
event_key='ORDER-20260611-001', # 幂等键
total_amount=Decimal('100.00'),
participants={
'worker': 'dashou_123',
},
payload={'order_id': 'xxx', 'game': 'LoL', 'shop_id': 'shop_001'},
)
# records = [
# {ParticipantID: 'dashou_123', ParticipantRole: 'worker', Amount: 80},
# {ParticipantID: 'platform_default', ParticipantRole: 'platform', Amount: 20},
# ]
9.2 会员购买+邀请链
# 配置会员购买分佣规则
engine.ConfigureRule(
event_type='member_purchase',
rule_name='会员购买管事+组长分红',
participant_rules=[
{'role': 'agent', 'type': 'fixed', 'value': 10},
{'role': 'leader', 'type': 'fixed', 'value': 5},
{'role': 'platform', 'type': 'remainder'},
],
)
# 打手购买会员 → 触发邀请链分佣
records = engine.BuildInviteChainCommission(
event_type='member_purchase',
event_key='MEMBER-VIP001-20260611-001',
total_amount=Decimal('50.00'),
source_user_uuid='dashou_123',
invite_chain=[
{'user_uuid': 'guanshi_456', 'level': 1, 'role': 'agent'},
{'user_uuid': 'zuzhang_789', 'level': 2, 'role': 'leader'},
],
rule_name='会员购买管事+组长分红',
participant_rules=[
{'role': 'agent', 'type': 'fixed', 'value': 10},
{'role': 'leader', 'type': 'fixed', 'value': 5},
{'role': 'platform', 'type': 'remainder'},
],
)
# records = [
# {ParticipantID: 'guanshi_456', ParticipantRole: 'agent', Amount: 10},
# {ParticipantID: 'zuzhang_789', ParticipantRole: 'leader', Amount: 5},
# {ParticipantID: 'platform_default', ParticipantRole: 'platform', Amount: 35},
# ]
9.3 阶梯分佣(多次购买)
# 第一次购买
engine.Dispatch(
event_type='member_purchase',
event_key='STAGED-VIP001-DASHOU_123-1',
total_amount=Decimal('50.00'),
tier_index=1,
participants={'agent': 'guanshi_456'},
)
# 第二次购买(金额不同)
engine.Dispatch(
event_type='member_purchase',
event_key='STAGED-VIP001-DASHOU_123-2',
total_amount=Decimal('50.00'),
tier_index=2,
participants={'agent': 'guanshi_456'},
)
9.4 提现手续费
# 配置提现费率表
engine.ConfigureRateTable(
table_code='withdrawal_fee',
table_name='提现手续费率',
entries={
'dashou': '0.0100', # 打手提现 1%
'guanshi': '0.0100', # 管事提现 1%
'zuzhang': '0.0100', # 组长提现 1%
},
)
# 计算手续费
fee = engine.CalculateFee(
total_amount=Decimal('1000.00'),
rate_table_code='withdrawal_fee',
rate_key='dashou',
)
# fee = 10.00 → 实际到账 990.00
9.5 跨平台预结算
# 创建预结算
ps = engine.PreSettle(
event_key='ORDER-CROSS-001',
external_platform='partner_club_002',
external_order_id='P-ORDER-888',
participant_id='dashou_123',
amount=Decimal('80.00'),
order_amount=Decimal('100.00'),
)
# 对方确认后
engine.ConfirmPreSettlement(
event_key='ORDER-CROSS-001',
confirmed_by='partner_admin',
)
十、与支付模块的关系
┌────────────────────────────────────────────────────────────┐
│ 子服务业务层 │
│ │
│ 订单完成 ──→ CommissionEngine.Dispatch() ──→ 算出分账 │
│ │ │
│ ▼ │
│ 用户提现 ──→ PaymentManager.Transfer() ──→ 执行打款 │
│ │
└────────────────────────────────────────────────────────────┘
分佣引擎 → 算出来"该分多少"
支付网关 → 执行"怎么打到账"
两者通过 CommissionRecord.Amount 桥接:
· CommissionRecord 中的分账金额作为 PaymentManager.Transfer 的输入
· 打款完成后,CommissionRecord 状态从 'settled' → 'withdrawn'
十一、配置变更记录
| 文件 | 变更 |
|---|---|
settings.py |
新增 'gvsds.apps.commission' 到 INSTALLED_APPS |
db_router.py |
新增 'commission': 'default' 到 app_db_map |
urls.py |
新增 path('api/commission/', include('gvsds.apps.commission.urls')) |