Add shareholder revenue plan and Shopro uni-app package.
Co-authored-by: Cursor <cursoragent@cursor.com>
这个提交包含在:
860
docs/合伙股东收益体系二次开发文档.md
普通文件
860
docs/合伙股东收益体系二次开发文档.md
普通文件
@@ -0,0 +1,860 @@
|
||||
# 恒连数通 · 合伙股东收益体系完整技术方案
|
||||
|
||||
> 版本:V2.0(基于现有前后端代码重写)
|
||||
> 日期:2026-09-16
|
||||
> 代码基线:本仓库 Shopro Plus **3.2.0** + FastAdmin
|
||||
> 用户端基线:官方 **sheep uni-app**(`SHOPRO_API_PATH=/addons/shopro/`)
|
||||
> 状态:可排期实施方案(业务未拍板项见第 16 节,开发按建议默认)
|
||||
|
||||
---
|
||||
|
||||
## 0. 先说清楚现在仓库里有什么
|
||||
|
||||
| 部分 | 位置 | 结论 |
|
||||
|---|---|---|
|
||||
| 商城后端 | 本仓库 `addons/shopro`、`application/admin` | 完整,Shopro Plus 3.2.0 |
|
||||
| 管理后台前端 | 本仓库 `application/admin/view/shopro` + `public/assets/js/backend/shopro` | 完整,Element Plus + RequireJS |
|
||||
| 用户端 uni-app | **不在本仓库** | 官方 sheep 结构,接口已备好;本地未找到恒连数通前端工程 |
|
||||
| 现有分销 | 三级百分比佣金 + 分销商等级升级 | 能复用关系链 / 支付钩子 / 钱包 / 团队统计,**不能直接算**固定金额奖、均分、马豆、释放券 |
|
||||
|
||||
用户端若已上线,一般是独立 sheep 工程,请求前缀:
|
||||
|
||||
```
|
||||
{SHOPRO_BASE_URL}/addons/shopro/{controller.action}
|
||||
Header: token + platform
|
||||
```
|
||||
|
||||
对照本地另一套 Shopro Plus 前端(`/Users/chen/Desktop/xbiuld/理发店`),页面和接口命名与本后端完全对得上。本方案用户端改动按这套 sheep 写。**开工前请把恒连数通 uni-app 放进工作区。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 现有代码如何运转(必须顺着改,不能另起炉灶)
|
||||
|
||||
### 1.1 关系链
|
||||
|
||||
- 字段:`fa_user.parent_user_id`
|
||||
- `NULL` = 未锁定
|
||||
- `0` = 平台直推
|
||||
- `>0` = 上级用户
|
||||
- 绑定只发生一次:`addons/shopro/service/commission/Agent.php::bindUserRelation()`
|
||||
- 绑定时机由 `shop.commission.invite_lock` 决定:`share` / `pay` / `agent`
|
||||
- 当 `become_agent.type = user` 时,锁定事件被强制成 `agent`(注册即绑)
|
||||
- 后台改上级:`shopro/commission/agent/changeParentUser`,已有环检测
|
||||
|
||||
**本体系全部「直推 / 伞下 / 关系链」继续只用这一条链,禁止再做第二套推荐关系。**
|
||||
|
||||
### 1.2 支付后分销(现网真实链路)
|
||||
|
||||
```
|
||||
PayOper 支付成功
|
||||
→ Queue shopro-high : OrderPaid@paid
|
||||
→ Hook order_paid_after
|
||||
① listener\Order::orderPaidAfter
|
||||
累计 user.total_consume、发货
|
||||
② listener\Commission::orderPaidAfter
|
||||
bindUserRelation('pay')
|
||||
每个 order_item:
|
||||
OrderService::checkAndSetCommission()
|
||||
createCommissionOrder() // fa_shopro_commission_order
|
||||
runCommissionPlan() // 按 1/2/3 级百分比写 fa_shopro_commission_reward
|
||||
RewardService('paid')::runCommissionRewardByOrder()
|
||||
createNewAgent()
|
||||
createAsyncAgentUpgrade() // Queue shopro : Commission@agentUpgrade
|
||||
```
|
||||
|
||||
积分订单 `order.type === 'score'` 整单跳过。
|
||||
货到付款走 `order_offline_paid_after`,同一套逻辑。
|
||||
|
||||
结算节点由 `shop.commission.reward_event` 控制:`paid` / `confirm` / `finish`。
|
||||
入账:`Wallet::change($user, 'commission', $amount, 'reward_income')`。
|
||||
|
||||
### 1.3 退款回滚
|
||||
|
||||
唯一有效钩子:`order_item_refund_after` → `Commission::orderItemRefundAfter`。
|
||||
售后完成本身(`order_aftersale_completed`)**不会**回滚佣金,必须发生真实退款。
|
||||
|
||||
回滚受两个开关控制:
|
||||
|
||||
- `shop.commission.refund_commission_reward`
|
||||
- `shop.commission.refund_commission_order`
|
||||
|
||||
已入账用 `reward_back` 扣佣金钱包(允许扣成负)。
|
||||
|
||||
### 1.4 钱包(只有三种)
|
||||
|
||||
`Wallet::change()` 白名单:`money` / `score` / `commission`。
|
||||
对应 `fa_user` 三列 + `fa_shopro_user_wallet_log`。
|
||||
|
||||
现有佣金事件:`reward_income` / `reward_back` / `withdraw` / `withdraw_error` / `transfer_to_money`。
|
||||
|
||||
**现金类新收益全部进 `commission`,加新 event,不要新开第四种可提现钱包。**
|
||||
马豆、兑换券不能塞进这三种,否则流水和提现会乱。
|
||||
|
||||
### 1.5 分销商与升级
|
||||
|
||||
表:`fa_shopro_commission_agent`(主键 `user_id`)
|
||||
|
||||
已有业绩字段(升级引擎直接用):
|
||||
|
||||
- `child_order_count_0/1/2/all`、`child_order_money_*`
|
||||
- `child_user_count_*`、`child_agent_count_*`
|
||||
- `child_agent_level_1`、`child_agent_level_all`(JSON,可配「伞下有 N 个某等级」)
|
||||
|
||||
升级:`Agent::runAgentUpgradePlan()` → `isMatchUpgradeLevelRule()`。
|
||||
条件可配:消费、直推人数、团队订单数、伞下某等级人数。
|
||||
`upgrade_type=0` 满足一条即可,`=1` 必须全满足。
|
||||
|
||||
成为分销商:`shop.commission.become_agent.type`
|
||||
|
||||
| type | 含义 |
|
||||
|---|---|
|
||||
| `user` | 注册即是 |
|
||||
| `goods` | 买指定商品 |
|
||||
| `consume` | 累计消费达标 |
|
||||
| `apply` | 自行申请 |
|
||||
|
||||
### 1.6 用户端现有接口(sheep 已对接)
|
||||
|
||||
| sheep 调用 | 后端 | 现状 |
|
||||
|---|---|---|
|
||||
| `GET commission.agent` | `addons/shopro/controller/commission/Agent::index` | 返回 agent + `level_info.name/image`,未成为则 code 100 |
|
||||
| `GET commission.agent/team` | 同上 `team` | **只查直推** `parent_user_id=我` |
|
||||
| `GET commission.order` | `commission/Order::index` | 分销订单 + 本人 rewards |
|
||||
| `GET commission.log` | `commission/Log::index` | 动态 |
|
||||
| `POST commission.agent/transfer` | 佣金转余额 | 已可用 |
|
||||
| `GET user.user/profile` | `user/User::profile` | money / commission / score,**无身份徽章字段** |
|
||||
| `GET user.wallet_log?type=commission` | 佣金流水 | event 文案来自 WalletLog::$eventMap |
|
||||
| `GET user.coupon` | Shopro 优惠券 | **一次性券,不能按天释放** |
|
||||
|
||||
分销中心关闭条件:`shop.commission.level == 0` → 接口直接 101。
|
||||
**禁止把 level 设成 0 来关旧百分比**,否则整个「分销中心」前端挂掉。
|
||||
|
||||
### 1.7 管理后台现有页
|
||||
|
||||
`shopro/commission` 下已有:分销商、等级、分销订单、佣金、动态、分销商品。
|
||||
配置页:`shopro/config/commission`。
|
||||
等级编辑页文案仍是「等级佣金比例」,要改成「创客级差金额」。
|
||||
|
||||
### 1.8 定时任务现状
|
||||
|
||||
**没有日结 cron。**
|
||||
`Shopro::appInit()` 只注册了 `shopro:chat`、`shopro:help`。
|
||||
队列:`shopro-high`(支付)、`shopro`(升级 / 自动收货)。
|
||||
优惠券没有「每天释放一点」的能力。
|
||||
|
||||
---
|
||||
|
||||
## 2. 总体策略:在 Shopro 分销内核上长一层,不新开插件
|
||||
|
||||
上一版「独立 `addons/partner`」在对账、退款、前端上会和现网裂开。V2 改为:
|
||||
|
||||
```
|
||||
保留
|
||||
parent_user_id
|
||||
成为分销商 / 升级队列
|
||||
团队人数与订单统计
|
||||
支付 / 退款钩子
|
||||
佣金钱包 + 提现 + 转余额
|
||||
sheep 分销中心页面骨架
|
||||
|
||||
关掉(配置,不删代码)
|
||||
runCommissionPlan 的百分比 1/2/3 级分佣
|
||||
|
||||
新增
|
||||
身份扩展(酒道馆 / 区县)
|
||||
固定金额结算器 PartnerReward
|
||||
马豆账户 + 汇率
|
||||
兑换券释放计划
|
||||
00:30 日结命令
|
||||
后台规则页 + 流水页
|
||||
sheep 徽章 / 马豆 / 兑换券页
|
||||
```
|
||||
|
||||
原则:
|
||||
|
||||
1. 旧 `runCommissionPlan` 用开关跳过,历史佣金不动。
|
||||
2. 新收益写入新表 `fa_shopro_partner_reward`,现金入账仍走 `Wallet::change(..., 'commission', ...)`。
|
||||
3. 用户端继续打 `commission.agent`,只扩展返回字段和加少量新接口。
|
||||
4. 品酒师 ↔ 创客互斥,用 `agent.level` 表达,不再做第二套等级。
|
||||
|
||||
---
|
||||
|
||||
## 3. 身份如何落到现有表
|
||||
|
||||
### 3.1 等级复用 `fa_shopro_commission_level`
|
||||
|
||||
上线时初始化 7 条等级(后台可改名称和徽章图):
|
||||
|
||||
| level | 名称 | 业务身份 | 单笔极差基数(建议) |
|
||||
|---|---|---|---|
|
||||
| 1 | 品酒师 | 普通会员 | 0(不参与极差) |
|
||||
| 2 | 创客V1 | 合伙股东·创客 | 20 |
|
||||
| 3 | 创客V2 | 合伙股东·创客 | 40 |
|
||||
| 4 | 创客V3 | 合伙股东·创客 | 60 |
|
||||
| 5 | 创客V4 | 合伙股东·创客 | 80 |
|
||||
| 6 | 创客V5 | 合伙股东·创客 | 100 |
|
||||
| 7 | 创客V6 | 合伙股东·创客 | 120 |
|
||||
|
||||
判定:
|
||||
|
||||
```
|
||||
是品酒师 = agent 存在且 level == 1
|
||||
是创客 = agent 存在且 level >= 2
|
||||
合伙股东 = 创客 或 酒道馆 或 区县代理
|
||||
```
|
||||
|
||||
一个人只有一个 `level`,所以**不可能同时是品酒师和创客**,与需求一致。
|
||||
创客继承品酒师收益:结算器判断「品酒师奖」时用 `level >= 1`,不要求 `== 1`。
|
||||
|
||||
### 3.2 酒道馆 / 区县:加在 agent 上,不新建用户身份表
|
||||
|
||||
```sql
|
||||
ALTER TABLE `fa_shopro_commission_agent`
|
||||
ADD COLUMN `is_venue` tinyint(1) NOT NULL DEFAULT 0 COMMENT '酒道馆' AFTER `level`,
|
||||
ADD COLUMN `is_county` tinyint(1) NOT NULL DEFAULT 0 COMMENT '区县代理' AFTER `is_venue`,
|
||||
ADD COLUMN `county_code` varchar(20) NOT NULL DEFAULT '' COMMENT '区县编码' AFTER `is_county`,
|
||||
ADD COLUMN `direct_order_seq` int(11) NOT NULL DEFAULT 0 COMMENT '直推合格单累计(推三返一)' AFTER `county_code`,
|
||||
ADD COLUMN `madow` decimal(20,8) NOT NULL DEFAULT 0.00000000 COMMENT '马豆' AFTER `direct_order_seq`,
|
||||
ADD COLUMN `voucher_total` decimal(12,2) NOT NULL DEFAULT 0.00 AFTER `madow`,
|
||||
ADD COLUMN `voucher_released` decimal(12,2) NOT NULL DEFAULT 0.00 AFTER `voucher_total`,
|
||||
ADD COLUMN `voucher_used` decimal(12,2) NOT NULL DEFAULT 0.00 AFTER `voucher_released`,
|
||||
ADD KEY `idx_venue` (`is_venue`),
|
||||
ADD KEY `idx_county` (`is_county`);
|
||||
```
|
||||
|
||||
可叠加:创客V5 + 酒道馆 + 区县代理 是合法的。
|
||||
|
||||
「30 日必须有自己的订单」用现成 `fa_user` + 订单表查,不冗余存;可加缓存字段 `last_self_order_time` 到 agent,支付成功时更新,日结用索引扫。
|
||||
|
||||
```sql
|
||||
ALTER TABLE `fa_shopro_commission_agent`
|
||||
ADD COLUMN `last_self_order_time` bigint(16) DEFAULT NULL COMMENT '本人最近合格订单时间' AFTER `voucher_used`,
|
||||
ADD KEY `idx_last_self_order` (`last_self_order_time`);
|
||||
```
|
||||
|
||||
### 3.3 注册即品酒师(建议默认)
|
||||
|
||||
后台把分销设置改成:
|
||||
|
||||
- `become_agent.type = user`(注册即分销商)
|
||||
- `agent_check = 0`
|
||||
- `agent_form.status = 0`
|
||||
- `invite_lock` 保持 `share`(分享即锁上级;因 become=user 时代码会改成 `agent`,需改一处,见 7.2)
|
||||
- `self_buy` 按业务,推三返一默认不含自购
|
||||
- `reward_event = paid`
|
||||
- `level` 保持 `>= 1`(分销中心开着)
|
||||
- 新增 `shop.commission.partner_mode = 1`(跳过百分比分佣)
|
||||
|
||||
需求里「直推 3 单或伞下有人升级才是品酒师」与「默认都是品酒师」冲突。
|
||||
**开发按注册即 level=1。** 若改口,再把 `become_agent` 换成 `goods/consume` 或自定义升级到 level=1。
|
||||
|
||||
### 3.4 创客 / 酒道馆 / 区县怎么来(需求未写)
|
||||
|
||||
| 身份 | 建议默认 | 现成能力 |
|
||||
|---|---|---|
|
||||
| 创客 V1-V6 | 后台改 `agent.level`;同时把 V2-V6 的 `upgrade_rules` 配上(直推人数、团队单数、伞下创客数),走现有 `agentUpgrade` 队列 | `shopro/commission/level` + `agent/edit` |
|
||||
| 酒道馆 | 仅后台勾选 `is_venue` | 新字段,agent 编辑页加开关 |
|
||||
| 区县代理 | 仅后台勾选 `is_county`,选区县 | 区县数据复用 `shopro/data/area` |
|
||||
|
||||
未拍板前**不要写死**「买某某套餐升酒道馆」。升级条件全部进等级规则 JSON。
|
||||
|
||||
---
|
||||
|
||||
## 4. 计奖总闸
|
||||
|
||||
### 4.1 合格订单
|
||||
|
||||
与现网分销对齐,减少口径分裂:
|
||||
|
||||
- `fa_shopro_order`,`type != score`
|
||||
- 状态 `paid` 或 `completed`
|
||||
- 商品 `fa_shopro_commission_goods.status = 1`(继续用「是否参与分销」当「是否参与本体系」)
|
||||
- 实付 `pay_fee > 0`
|
||||
- **计 1 单 = 1 个订单头**(不按件数)。推三返一、团队拆分、平台均分、汇率 N 同一口径
|
||||
|
||||
`createCommissionOrder()` 今天按 **order_item** 写业绩。partner_mode 下:
|
||||
|
||||
- 仍写一条 `shopro_commission_order`(沿用退款钩子、业绩、升级)
|
||||
- 但 `runCommissionPlan` 不跑
|
||||
- `PartnerReward` **按订单头只算一次**(用 `order_id` 幂等,不按 item 乘倍数)
|
||||
|
||||
### 4.2 30 日活跃
|
||||
|
||||
```
|
||||
active = 存在本人合格订单
|
||||
AND paid_time >= 今日0点 - 29天 -- 含今天共 30 个自然日
|
||||
```
|
||||
|
||||
实现:优先 `agent.last_self_order_time`,没有则查订单。
|
||||
|
||||
| 奖项 | 不活跃时 |
|
||||
|---|---|
|
||||
| 推三返一 / 极差 / 平级 / 团队拆分 | 该受益人跳过,**不顺延**给再上一级;极差**不占用水位** |
|
||||
| 平台均分(酒道馆 100、区县 50、马豆) | 不进分母 |
|
||||
| 买家兑换券 | 本次下单即活跃,照发 |
|
||||
|
||||
### 4.3 关系链遍历
|
||||
|
||||
新建 `addons/shopro/service/partner/ChainService.php`:
|
||||
|
||||
```
|
||||
从 buyer.parent_user_id 向上走
|
||||
最多 partner.chain_max_depth(默认 50)
|
||||
只收集 agent.status in (normal, freeze)
|
||||
返回节点:user_id, level, is_venue, is_county, last_self_order_time
|
||||
```
|
||||
|
||||
复用 `Agent::getParentUserId()`,不要 SQL 递归。
|
||||
|
||||
---
|
||||
|
||||
## 5. 收益规则(算法冻结稿)
|
||||
|
||||
现金一律进佣金钱包。马豆、兑换券进 agent 扩展字段。
|
||||
|
||||
### 5.1 品酒师 · 推三返一
|
||||
|
||||
业务对齐:398 + 400 + 600 = **1398**(推 3 单返 1 件货的钱),之后循环。
|
||||
|
||||
- 受益人:买家直推上级,且 `level >= 1`,且 30 日活跃
|
||||
- 自购不发
|
||||
- 序号:`agent.direct_order_seq`(受益人维度,每成功计 1 次 +1)
|
||||
|
||||
```
|
||||
seq = (direct_order_seq % 3) // +1 之后
|
||||
amount = [398, 400, 600][ (seq-1) % 3 ]
|
||||
```
|
||||
|
||||
退款:金额 `reward_back`,`direct_order_seq -= 1`(≥0),下一单顶原序号。
|
||||
|
||||
### 5.2 品酒师 · 每日 1:1 + 马豆汇率
|
||||
|
||||
原文若按现金 1:1 发当天 GMV,毛利为负。
|
||||
**默认:发马豆,只展示人民币价值,不能提现。**
|
||||
|
||||
日结(昨天 00:00:00–23:59:59):
|
||||
|
||||
```
|
||||
G = 昨日合格订单 pay_fee 合计
|
||||
users = last_self_order_time 落在 [昨天-29天, 昨天] 的品酒师/创客(level>=1, status 可用)
|
||||
每人马豆 = G / count(users) // 8 位小数,尾差进平台账户 user_id=0
|
||||
```
|
||||
|
||||
汇率:
|
||||
|
||||
```
|
||||
base = 0.00000075
|
||||
n = 配置 partner.madow.step_orders,默认 1
|
||||
N = 平台历史合格订单累计(支付成功;退款默认不减)
|
||||
rate = base * floor(N / n)
|
||||
展示价值 = agent.madow * rate
|
||||
```
|
||||
|
||||
`N`、`rate` 每天写入 `fa_shopro_partner_rate_log`,前端读最新一行。
|
||||
|
||||
### 5.3 品酒师 · 兑换券 1.5 倍 / 365 天
|
||||
|
||||
不进 `fa_shopro_coupon`(那是一次性优惠券)。
|
||||
|
||||
```
|
||||
总额 = 订单实付 * 1.5 // 1398 → 2097
|
||||
次日 00:30 起释放 365 天
|
||||
每天 = 总额/365,最后一天补尾差
|
||||
可用 = released - used
|
||||
```
|
||||
|
||||
结算抵扣:在 `OrderCreate` 增加 `voucher_fee`,扣 `voucher_used`。可与余额混付。默认不过期、不转赠。
|
||||
|
||||
### 5.4 创客 · 极差奖
|
||||
|
||||
基数:`level_bonus = {2:20, 3:40, 4:60, 5:80, 6:100, 7:120}`,后台可改。
|
||||
从近到远扫链上 `level>=2` 且活跃的创客:
|
||||
|
||||
```
|
||||
seen = 0
|
||||
for agent in chain_makers:
|
||||
cap = level_bonus[agent.level]
|
||||
if cap <= seen: continue // 平级或更低,无极差
|
||||
pay = cap - seen
|
||||
入账 pay
|
||||
seen = cap
|
||||
```
|
||||
|
||||
例:V1(level2) → V3(level4) → V6(level7) = 20 + 40 + 60。
|
||||
不活跃的人跳过且不抬 `seen`。
|
||||
|
||||
### 5.5 创客 · 平级 10% / 被超越 5%
|
||||
|
||||
与示例「V5 的 100 × 10% = 10」对齐:基数用**等级标准佣金**,不是本单极差实得。
|
||||
|
||||
- 平级:刚拿到极差的人再向上,**最近一个同 level** 得 `level_bonus × 10%`,只一层
|
||||
- 被超越:向上**最近一个 level 更低的创客**得 `本次最高水位基数 × 5%`,每单都算,只一层
|
||||
|
||||
### 5.6 酒道馆 / 区县 · 团队拆分(方案 I,防重复)
|
||||
|
||||
一单只切 **100 元**,不要酒道馆先拿 50 再拿区县那 50。
|
||||
|
||||
```
|
||||
nearest_venue = 链上最近 is_venue=1 且活跃
|
||||
nearest_county = 链上最近 is_county=1 且活跃
|
||||
(若有酒道馆,区县必须在该酒道馆之上)
|
||||
|
||||
无酒道馆有区县:区县 100
|
||||
有酒道馆有区县:酒道馆 50 + 其上最近区县 50
|
||||
有酒道馆无区县:酒道馆 50
|
||||
都无:不发
|
||||
自购且自己是酒道馆:自己算最近酒道馆
|
||||
```
|
||||
|
||||
### 5.7 酒道馆平级 10%
|
||||
|
||||
基数 = 本单该下级的 `team_venue`(50),**不含**创客收益、**不含**平台均分。
|
||||
向上最近一个酒道馆拿 5 元。
|
||||
|
||||
### 5.8 区县平级 10%
|
||||
|
||||
基数 = 本单该下级的 `team_county`(50 或 100)。
|
||||
向上最近一个区县拿 10%。
|
||||
|
||||
### 5.9 平台均分(日结)
|
||||
|
||||
| 奖池 | 公式 | 分母 |
|
||||
|---|---|---|
|
||||
| 酒道馆 | 昨日单数 × 100 | `is_venue=1` 且活跃 |
|
||||
| 区县 | 昨日单数 × 50 | `is_county=1` 且活跃 |
|
||||
|
||||
分母为 0:进平台账户。尾差进平台。
|
||||
与 5.2 同一条日结命令,00:30 跑昨天。
|
||||
|
||||
---
|
||||
|
||||
## 6. 一单拆账示例
|
||||
|
||||
买家 U0,链:U1 品酒师 → U2 创客V5 → U3 创客V5 → U4 创客V6+酒道馆 → U5 区县。
|
||||
U1 直推本单是第 1 单,全部活跃。实付 1398。
|
||||
|
||||
| 人 | 即时现金 | 说明 |
|
||||
|---|---|---|
|
||||
| U1 | 398 | 推三返一 |
|
||||
| U2 | 100 | 极差 V5 |
|
||||
| U3 | 10 | 平级 10% |
|
||||
| U4 | 20 + 50 | 极差 20 + 酒道馆拆分 50 |
|
||||
| U5 | 50 | 区县拆分 50 |
|
||||
| U4 的上级酒道馆 | 5 | 酒道馆平级 |
|
||||
| U5 的上级区县 | 5 | 区县平级 |
|
||||
|
||||
U0:兑换券额度 2097。
|
||||
日结另计:酒道馆均分、区县均分、马豆。
|
||||
|
||||
---
|
||||
|
||||
## 7. 后端改哪些文件
|
||||
|
||||
### 7.1 新增
|
||||
|
||||
```
|
||||
addons/shopro/service/partner/ChainService.php
|
||||
addons/shopro/service/partner/ActiveService.php
|
||||
addons/shopro/service/partner/PartnerRewardService.php // 订单即时奖入口
|
||||
addons/shopro/service/partner/Push3Reward.php
|
||||
addons/shopro/service/partner/MakerDiffReward.php
|
||||
addons/shopro/service/partner/MakerPeerReward.php
|
||||
addons/shopro/service/partner/TeamSplitReward.php
|
||||
addons/shopro/service/partner/PeerShareReward.php
|
||||
addons/shopro/service/partner/DailySettleService.php
|
||||
addons/shopro/service/partner/MadowService.php
|
||||
addons/shopro/service/partner/VoucherService.php
|
||||
addons/shopro/service/partner/RateService.php
|
||||
addons/shopro/job/PartnerSettle.php // 队列:单笔订单
|
||||
addons/shopro/console/PartnerSettle.php // php think shopro:partner:settle
|
||||
addons/shopro/controller/partner/Index.php // 用户端:概览/马豆/兑换券/流水
|
||||
application/admin/controller/shopro/partner/Reward.php
|
||||
application/admin/controller/shopro/partner/Daily.php
|
||||
application/admin/controller/shopro/partner/Voucher.php
|
||||
application/admin/model/shopro/partner/Reward.php
|
||||
application/admin/model/shopro/partner/RateLog.php
|
||||
application/admin/model/shopro/partner/VoucherPlan.php
|
||||
application/admin/model/shopro/partner/DailyReport.php
|
||||
```
|
||||
|
||||
SQL 放 `addons/shopro/upgrade/partner_v2.sql`,手工执行(本项目没有自动 migration)。
|
||||
|
||||
### 7.2 必改的现有文件(尽量小)
|
||||
|
||||
| 文件 | 改什么 |
|
||||
|---|---|
|
||||
| `addons/shopro/hooks.php` | `order_paid_after` / `order_offline_paid_after` / `order_item_refund_after` 增加 `listener\Partner` |
|
||||
| `addons/shopro/listener/Partner.php` | **新建**。支付入队 `PartnerSettle`;退款调回滚。不改 `Commission.php` 主体 |
|
||||
| `addons/shopro/service/commission/Order.php::runCommissionPlan` | 若 `sheep_config('shop.commission.partner_mode')` 则直接 return |
|
||||
| `addons/shopro/service/commission/Config.php` | `getInviteLockEvent()`:partner 模式下 become=user 仍允许 `invite_lock=share`,否则注册即绑会丢掉分享关系 |
|
||||
| `addons/shopro/service/commission/Agent.php` | 支付后更新 `last_self_order_time`;`createNewAgent` 默认 level=1 |
|
||||
| `application/admin/model/shopro/commission/Agent.php` | 新字段、append 身份文案 |
|
||||
| `addons/shopro/controller/commission/Agent.php::index` | 返回值加 `identities` / `madow` / `madow_value` / `voucher_*` / `rate` |
|
||||
| `addons/shopro/controller/user/User.php::profile` | 附加轻量身份(徽章用,避免再打一次 agent) |
|
||||
| `application/admin/model/shopro/user/WalletLog.php` | eventMap 增加 `push3` `maker_diff` `maker_peer` `maker_overtaken` `team_venue` `team_county` `venue_peer` `county_peer` `venue_share` `county_share` |
|
||||
| `addons/shopro/Shopro.php::appInit` | 注册 `shopro:partner:settle` |
|
||||
| `addons/shopro/service/order/OrderCreate.php` | 兑换券抵扣 |
|
||||
| `application/admin/controller/shopro/commission/Agent.php` | 编辑页:酒道馆/区县开关 |
|
||||
| `application/admin/controller/shopro/Config.php` | 分销配置增加 partner 分组 |
|
||||
| `addons/shopro/config/menu.php` | 菜单:收益流水、日结、兑换券 |
|
||||
|
||||
`Wallet::change` 的 `$event` 是自由字符串,**不用改 Wallet.php**,只要补 eventMap 文案。
|
||||
|
||||
### 7.3 支付 / 退款时序(改完后)
|
||||
|
||||
```
|
||||
order_paid_after
|
||||
Commission::orderPaidAfter // 写 commission_order、升级、(partner_mode 跳过百分比)
|
||||
Partner::orderPaidAfter
|
||||
更新 last_self_order_time
|
||||
Queue::push PartnerSettle@order, {order_id}, shopro-high
|
||||
|
||||
PartnerSettle@order
|
||||
锁 order_id
|
||||
推三返一 / 极差 / 平级 / 团队拆分 / 角色平级
|
||||
写 voucher_plan
|
||||
N += 1(内存计数表或 rate 服务)
|
||||
Wallet::change commission + 各 event
|
||||
每条 partner_reward 唯一键防重
|
||||
|
||||
order_item_refund_after
|
||||
Commission 原逻辑(业绩)
|
||||
Partner::refund
|
||||
回滚该 order_id 下 status=1 的即时奖
|
||||
推三返一序号 -1
|
||||
关闭兑换券计划并扣未使用已释放
|
||||
日结均分 / 马豆 / 汇率 N 不回溯
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 新表
|
||||
|
||||
### 8.1 `fa_shopro_partner_reward`
|
||||
|
||||
```sql
|
||||
CREATE TABLE `fa_shopro_partner_reward` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`order_id` int(11) NOT NULL DEFAULT 0,
|
||||
`buyer_id` int(11) NOT NULL DEFAULT 0,
|
||||
`user_id` int(11) NOT NULL COMMENT '受益人',
|
||||
`role` varchar(20) NOT NULL DEFAULT '' COMMENT 'taster/maker/venue/county/system',
|
||||
`reward_type` varchar(32) NOT NULL,
|
||||
`amount` decimal(12,2) NOT NULL DEFAULT 0.00,
|
||||
`madow` decimal(20,8) NOT NULL DEFAULT 0.00000000,
|
||||
`base_amount` decimal(12,2) NOT NULL DEFAULT 0.00,
|
||||
`rate` decimal(16,10) NOT NULL DEFAULT 0.0000000000,
|
||||
`ext` text,
|
||||
`settle_date` date DEFAULT NULL,
|
||||
`status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '0待入账 1已入账 -1取消 -2退回',
|
||||
`createtime` bigint(16) DEFAULT NULL,
|
||||
`updatetime` bigint(16) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_order_user_type` (`order_id`,`user_id`,`reward_type`),
|
||||
UNIQUE KEY `uk_daily_user_type` (`settle_date`,`user_id`,`reward_type`),
|
||||
KEY `idx_user` (`user_id`,`reward_type`,`status`),
|
||||
KEY `idx_order` (`order_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='合伙股东收益';
|
||||
```
|
||||
|
||||
即时奖 `settle_date=NULL`,`order_id>0`。
|
||||
日结 `order_id=0`,靠 `uk_daily_user_type` 防重。MySQL 里 NULL 不撞唯一,日结必须写具体日期。
|
||||
|
||||
`reward_type`:`push3` `maker_diff` `maker_peer` `maker_overtaken` `team_venue` `team_county` `venue_peer` `county_peer` `venue_share` `county_share` `madow_share` `voucher_grant` `voucher_release`。
|
||||
|
||||
### 8.2 `fa_shopro_partner_voucher_plan`
|
||||
|
||||
```sql
|
||||
CREATE TABLE `fa_shopro_partner_voucher_plan` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL,
|
||||
`order_id` int(11) NOT NULL,
|
||||
`total_amount` decimal(12,2) NOT NULL,
|
||||
`daily_amount` decimal(12,2) NOT NULL,
|
||||
`released_amount` decimal(12,2) NOT NULL DEFAULT 0.00,
|
||||
`released_days` int(11) NOT NULL DEFAULT 0,
|
||||
`total_days` int(11) NOT NULL DEFAULT 365,
|
||||
`start_date` date NOT NULL,
|
||||
`status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '1释放中 2完成 0关闭',
|
||||
`createtime` bigint(16) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_order` (`order_id`),
|
||||
KEY `idx_user_status` (`user_id`,`status`,`start_date`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### 8.3 `fa_shopro_partner_rate_log` / `fa_shopro_partner_daily_report`
|
||||
|
||||
每日一行:`order_count_n, rate, gmv, madow_pool, share_user_count, venue_pool, county_pool`。
|
||||
对账表按奖项汇总发放、人数、失败原因。
|
||||
|
||||
### 8.4 配置(`fa_shopro_config`,分组 `shop.commission.partner`)
|
||||
|
||||
挂在现有分销设置页一个 Tab,不要另做一套 config 体系。
|
||||
|
||||
| code | 默认 |
|
||||
|---|---|
|
||||
| partner_mode | 1 |
|
||||
| active_days | 30 |
|
||||
| chain_max_depth | 50 |
|
||||
| push3_amounts | [398,400,600] |
|
||||
| madow_mode | madow |
|
||||
| madow_base_rate | 0.00000075 |
|
||||
| madow_step_orders | 1 |
|
||||
| voucher_times | 1.5 |
|
||||
| voucher_days | 365 |
|
||||
| maker_bonus | {2:20,3:40,4:60,5:80,6:100,7:120} |
|
||||
| maker_peer_rate | 0.10 |
|
||||
| maker_overtaken_rate | 0.05 |
|
||||
| team_total | 100 |
|
||||
| venue_split | 50 |
|
||||
| county_full | 100 |
|
||||
| venue_share_per_order | 100 |
|
||||
| county_share_per_order | 50 |
|
||||
| venue_peer_rate | 0.10 |
|
||||
| county_peer_rate | 0.10 |
|
||||
|
||||
---
|
||||
|
||||
## 9. 用户端 API(sheep 风格)
|
||||
|
||||
原接口只扩展字段,前端少改路由。
|
||||
|
||||
### 9.1 扩展 `GET /addons/shopro/commission.agent`
|
||||
|
||||
在现有 agent 上增加:
|
||||
|
||||
```json
|
||||
{
|
||||
"identities": ["taster"],
|
||||
"identity_text": "品酒师",
|
||||
"is_partner": false,
|
||||
"is_venue": 0,
|
||||
"is_county": 0,
|
||||
"madow": "0.00000000",
|
||||
"madow_rate": "0.00000075",
|
||||
"madow_value": "0.00",
|
||||
"voucher_total": "0.00",
|
||||
"voucher_released": "0.00",
|
||||
"voucher_used": "0.00",
|
||||
"voucher_available": "0.00",
|
||||
"active_30d": true,
|
||||
"last_self_order_time": 0
|
||||
}
|
||||
```
|
||||
|
||||
`identities` 例:`["maker","venue"]`,`identity_text`:`合伙股东 · 创客V5 · 酒道馆`。
|
||||
徽章继续用 `level_info.name` + `level_info.image`,前端可再画酒道馆/区县小标。
|
||||
|
||||
### 9.2 扩展 `GET /addons/shopro/user.user/profile`
|
||||
|
||||
加同结构的轻量字段,个人中心不用先打 agent(未成为分销商时 agent 会 100)。
|
||||
注册即 agent 后,profile 与 agent 应对齐。
|
||||
|
||||
### 9.3 新增 `addons/shopro/controller/partner/Index.php`
|
||||
|
||||
| 方法 | 路径 | 作用 |
|
||||
|---|---|---|
|
||||
| index | `GET partner.index` | 今日预估、累计、按奖项汇总 |
|
||||
| rewards | `GET partner.index/rewards` | 分页流水,`reward_type` 筛选 |
|
||||
| madow | `GET partner.index/madow` | 马豆、汇率历史 |
|
||||
| voucher | `GET partner.index/voucher` | 计划列表 + 释放日历 |
|
||||
| daily | `GET partner.index/daily` | 最近日结(均分/马豆) |
|
||||
|
||||
钱包页继续 `user.wallet_log?type=commission`,新 event 会出现中文。
|
||||
收益分类明细走 `partner.index/rewards`,因为均分/马豆/券不是 wallet 三种类型能表达的。
|
||||
|
||||
---
|
||||
|
||||
## 10. 管理后台(本仓库就能做完)
|
||||
|
||||
### 10.1 改现有页
|
||||
|
||||
| 页 | 文件 | 改动 |
|
||||
|---|---|---|
|
||||
| 分销设置 | `view/shopro/config/index.html` + `js/backend/shopro/config.js` | 增加「合伙股东」Tab |
|
||||
| 分销商编辑 | `commission/agent` 的 edit | `is_venue` `is_county` `county_code` |
|
||||
| 分销商列表 | `agent.js` / `agent/index.html` | 筛酒道馆/区县,列身份 |
|
||||
| 等级 | `commission/level/add.html` | 文案改为级差基数;`commission_rules` 可空;展示 `maker_bonus[level]` |
|
||||
|
||||
### 10.2 新页(照现有 commission 列表复制)
|
||||
|
||||
| 菜单 | 控制器 | 能力 |
|
||||
|---|---|---|
|
||||
| 合伙股东 / 收益流水 | `shopro/partner/reward` | 筛选、导出、手工补发/扣回 |
|
||||
| 合伙股东 / 日结对账 | `shopro/partner/daily` | 按日看池子、重跑昨天 |
|
||||
| 合伙股东 / 兑换券 | `shopro/partner/voucher` | 计划、已释放、已使用 |
|
||||
|
||||
样式、筛选器、导出照抄 `commission/reward`。
|
||||
|
||||
---
|
||||
|
||||
## 11. 用户端 uni-app(sheep,工程不在本仓库)
|
||||
|
||||
对照官方页面,改这些文件即可,不必重做分销中心。
|
||||
|
||||
### 11.1 必改
|
||||
|
||||
| 文件 | 改动 |
|
||||
|---|---|
|
||||
| `sheep/store/user.js` | `defaultUserInfo` 加 madow / voucher / identities |
|
||||
| `sheep/api/commission.js` | 已有 agent,不用改 URL |
|
||||
| `sheep/api/partner.js` | **新建**,对 9.3 |
|
||||
| `pages/index/user.vue` | 头像下展示身份徽章(品酒师 / 合伙股东) |
|
||||
| `pages/commission/components/commission-info.vue` | 多徽章:创客等级 + 酒道馆 + 区县 |
|
||||
| `pages/commission/components/commission-menu.vue` | 增加:收益明细、马豆、兑换券 |
|
||||
| `pages/commission/index.vue` | 标题可改为「收益中心」 |
|
||||
| `pages.json` | 注册新页 |
|
||||
|
||||
### 11.2 新页
|
||||
|
||||
| 路径 | 内容 |
|
||||
|---|---|
|
||||
| `/pages/partner/rewards` | 按奖项流水,复用 commission-log 列表样式 |
|
||||
| `/pages/partner/madow` | 马豆数、汇率、约合人民币、说明 |
|
||||
| `/pages/partner/voucher` | 总额/已释放/可用、365 进度 |
|
||||
| `/pages/commission/team` | 直推列表加身份(后端 team 接口 with agent 已有 level,再加 is_venue/is_county) |
|
||||
|
||||
### 11.3 可后做
|
||||
|
||||
- 兑换专区:下单页勾兑换券,走 `OrderCreate` 的 `voucher_fee`
|
||||
- 分销商品页:百分比改展示「推三返一 / 极差说明」,或隐藏
|
||||
|
||||
团队接口今天只返回直推。伞下业绩继续看 agent 上已有的 `child_*`,不必一次拉整棵树。
|
||||
|
||||
---
|
||||
|
||||
## 12. 日结与运维
|
||||
|
||||
```
|
||||
# 宝塔 / crontab
|
||||
30 0 * * * cd /www/wwwroot/qbw.gynhc.com && php think shopro:partner:settle >> /tmp/partner_settle.log 2>&1
|
||||
```
|
||||
|
||||
命令:`addons/shopro/console/PartnerSettle.php`
|
||||
队列消费者保持现有:
|
||||
|
||||
```
|
||||
php think queue:work --queue shopro-high
|
||||
php think queue:work --queue shopro
|
||||
```
|
||||
|
||||
日结步骤:
|
||||
|
||||
1. 文件锁 `runtime/lock/partner_settle_{Ymd}`
|
||||
2. 统计昨日合格单数、GMV
|
||||
3. 写汇率快照
|
||||
4. 酒道馆均分、区县均分、马豆均分
|
||||
5. 释放兑换券一天
|
||||
6. 写 daily_report
|
||||
|
||||
同一 `settle_date` 已有成功报告则跳过。后台「重跑」先删当天日结流水再跑。
|
||||
|
||||
---
|
||||
|
||||
## 13. 开发分期(按本仓库可交付)
|
||||
|
||||
### P0 · 本仓库后端骨架(约 4–6 天)
|
||||
|
||||
- SQL + agent 字段
|
||||
- `partner_mode` 跳过百分比
|
||||
- 注册即 level=1(改配置 + Config 邀请锁)
|
||||
- 推三返一 + 兑换券计划
|
||||
- 支付队列 + 退款回滚
|
||||
- 日结命令先只做券释放
|
||||
- 后台:agent 开关、收益流水列表
|
||||
- 扩展 `commission.agent` / `profile` 返回值
|
||||
|
||||
验收:下一单,直推上级佣金钱包 +398/400/600,买家有券计划。
|
||||
|
||||
### P1 · 创客极差平级(约 3 天)
|
||||
|
||||
- maker_bonus 配置
|
||||
- 极差 + 平级 + 被超越
|
||||
- 等级页文案
|
||||
- 升级规则用现有 level 后台配
|
||||
|
||||
### P2 · 酒道馆 / 区县(约 3 天)
|
||||
|
||||
- 团队拆分 100
|
||||
- 两种角色平级
|
||||
- 日结两份均分
|
||||
|
||||
### P3 · 马豆(约 2 天)
|
||||
|
||||
- 日结分马豆
|
||||
- 汇率快照
|
||||
- agent 接口带价值
|
||||
|
||||
### P4 · 用户端 sheep(另仓,约 4 天,依赖 P0 接口)
|
||||
|
||||
- 徽章、菜单、三页、下单抵扣券
|
||||
|
||||
### P5 · 对账与售后(约 2 天)
|
||||
|
||||
- 日结重跑、导出
|
||||
- 部分退款、券已使用负债
|
||||
- 用例回归
|
||||
|
||||
---
|
||||
|
||||
## 14. 验收用例(按现网钩子写)
|
||||
|
||||
1. 新注册用户有 `shopro_commission_agent.level=1`,profile 为品酒师。
|
||||
2. 分享绑定后 `parent_user_id` 有值(partner 模式不因 become=user 丢掉 share)。
|
||||
3. 下级第 1/2/3/4 单,上级佣金流水 event 分别为 push3,金额 398/400/600/398。
|
||||
4. `partner_mode=1` 时 `shopro_commission_reward` **不再新增**百分比记录。
|
||||
5. 链 V1-V3-V6:20/40/60,佣金 event=`maker_diff`。
|
||||
6. 两个 V5:近的 100,远的 10(`maker_peer`)。
|
||||
7. 无酒道馆有区县:区县 +100;有两者:50+50,酒道馆平级只抽 50 的 10%。
|
||||
8. 上级 31 天无自购:本单他 0 收益,均分进不了分母。
|
||||
9. 整单退款:即时奖 `reward_back`,序号回退,券计划关闭。
|
||||
10. `php think shopro:partner:settle` 连续跑两次,日结流水不加倍。
|
||||
11. 1398 单券总额 2097,第 365 天补尾差。
|
||||
12. 同一人同时勾选创客+酒道馆+区县,三套收益都能出,且酒道馆平级不含创客极差。
|
||||
|
||||
---
|
||||
|
||||
## 15. 风险(结合现网)
|
||||
|
||||
| 风险 | 现网原因 | 处理 |
|
||||
|---|---|---|
|
||||
| 关 `commission.level=0` | Agent 基类直接 101,sheep 分销中心全挂 | 用 `partner_mode` 跳过百分比 |
|
||||
| become=user 丢掉分享关系 | `getInviteLockEvent()` 强制 `agent` | partner 模式改回尊重 `invite_lock` |
|
||||
| 按 item 计奖翻倍 | `orderPaidAfter` 循环 items | 即时奖按 `order_id` 幂等一次 |
|
||||
| 现金 1:1 GMV | 会把当日销售额再发一遍 | 默认马豆 |
|
||||
| 无 cron | 项目里没有日结命令 | 必须配 crontab,上线检查清单写死 |
|
||||
| uni-app 不在本仓 | 改完接口用户看不见 | 先交付 API,并行要前端工程 |
|
||||
| 旧分销数据 | 已有百分比佣金 | 只影响新单;旧单不重算 |
|
||||
| 队列没开 | 支付钩子已是异步 | 服务器确认 `queue:work` 两个队列都在 |
|
||||
|
||||
---
|
||||
|
||||
## 16. 仍需业务确认(不回则按括号内默认)
|
||||
|
||||
1. 品酒师:注册即是(默认)还是直推 3 单才是
|
||||
2. 1:1:马豆(默认)还是现金
|
||||
3. 汇率 n:默认 1;N=全平台累计;退款不减 N
|
||||
4. 马豆只展示(默认)还是可兑余额
|
||||
5. 创客/酒道馆/区县:先全后台开通(默认)
|
||||
6. 极差:水位差;不活跃不占水位(默认)
|
||||
7. 平级基数:等级标准佣金;只发一层(默认)
|
||||
8. 被超越:每单都发(默认)
|
||||
9. 酒道馆 50 与区县 50:同一笔 100(默认)
|
||||
10. 计单:订单头;参与分销的商品都算(默认)
|
||||
11. 30 日:自然日;份额作废不给上级(默认)
|
||||
12. 区域代理 = 区县代理;不独占行政区(默认)
|
||||
13. 兑换券:指定分类可兑、可混付、一直累计(默认)
|
||||
14. 旧百分比:新单关闭(默认)
|
||||
|
||||
---
|
||||
|
||||
## 17. 建议开工顺序(确认第 16 节后)
|
||||
|
||||
1. 把恒连数通 sheep 工程放进工作区或给仓库地址。
|
||||
2. 执行 `upgrade/partner_v2.sql`,改分销配置(become=user、partner_mode=1、七条等级)。
|
||||
3. 做 P0:钩子 + 推三返一 + 券计划 + agent 返回值。
|
||||
4. 用一笔真实支付单对流水(不要只看代码)。
|
||||
5. 再铺 P1–P3,最后对接 uni-app。
|
||||
|
||||
本仓库当前就能做完 **P0–P3 + 后台**。用户端页面必须有 sheep 工程才能改。
|
||||
在新工单中引用
屏蔽一个用户