核心结算功能 · 奖励逻辑(积分入账 → 释放 → 分红 → 去向)
适用范围:核心结算链路 M1–M3(T1–T10,计划 #84–#93),ThinkPHP 8 + PHP 8.2。 规则依据:《模式总结》——本文档以该文档为唯一权威口径,纠正旧版的多处错误理解(积分种类、入账公式、释放口径、分红叠加、动态加速等)。 命名说明:消费积分=
consume_point、兑换积分=exchange_point、锁仓积分=lock_point、专属红包=red_packet;★「兑换权益」=member.exchange_equity、「积分余额」=member.balance_point两个新增池的字段名已于 2026-09-12 确认。★ 最后更新 2026-09-18(v2026.09.18 · 向上/向下第 1 级比例 10%→5% + 有效用户资格 + 向下仅首层回退):本次补入/修正 7 处(①–⑦,2026-09-15)+ ⑧(09-17 无限层)+ ⑨(09-18 回退仅首层,见下)——
★ 2026-09-19 修正(需求 C 锁仓解冻基数/比例):礼包基数改明细原价
① §5.2 团队加速整体改写为 v2 三段式:分享奖order_item.amount(原扣券后实付);新增「推荐人 R 直发 10%」(lock_ref_rate,不递归);向上比例由 10% 修正为 1%(lock_up_rate=0.01);终止条件改为所得 < 0.01 即停。详见 §4.1。share+ 向上奖up+ 向下奖down,向上/向下各序列内逐级折半 0.5,中心 R = 买家的推荐人(2026-09-13 拍板「逐级递减 = 各方向序列内递减」,同日开关team_reward_v2_enable双线翻转); ② §2 总览「阶段 C」行同步 v2; ③ §7.1⑤ 加速奖基数改为「按区分叉」:礼包区订单 = 订单实付、其他区订单 = 让利额(非礼包入口accel_nongift_enable=1已放开,实时钩子在确认收货); ④ §11#4 状态更新:「向下」分支已实现投产,不再是留白;线②商户线不随 v2 变化(仍固定 10% pass-up); ⑤ 2026-09-14 正式线 v2 全量重置落账:14 单 48 行 v1 作废(全量备份*_bak),按 v2 重计提并发放 60 行 ¥26,094.82(burned=0); ⑥ 2026-09-14 比例修订(客户拍板):向上奖、向下奖第 1 级由 10% 下调为 5%(team_up_rate/team_down_rate0.10→0.05,即时生效),逐级折半不变;分享奖仍为 10% 不变;并自本日起计提后立即入账(礼包=支付后、其他=确认收货后,fund:payout转为兜底批处理); ⑦ ★2026-09-15 新增 §5.3「有效用户资格(礼包购买门槛)」:未买过礼包(has_gift_purchase=0)的账号即使status=1正常,其应得奖励(积分入账 / 加速奖)也视为不资格 → 全额烧伤归平台;礼包支付成功时GiftPostPay::handle置标、存量迁移补标,双线已投产(8/8 只读校验通过)。 ⑧ ★2026-09-17 团队加速「无限层 + 实发>0.01 才记录」(投产,详见 §5.4):向上team_up_max_level早已=0(无限制);向下team_down_max_level由 1 → 0(改无限制,沿下级树发到最深层);上/下行统一按actual(扣除烧伤后的真实发放额)严格 >team_down_min_amount(0.01)才落库,≤0.01 的碎额(深无限层尾部)直接 skip。生产只读探针验证:rebate=1000 时 maxDownLevel=10(原封顶 1,证无限层生效)、上/下行均无 actual≤0.01 碎额行;rebate=0.01 时全被门槛过滤(up=0/down=0)。 ⑨ ★2026-09-18 修正:向下层数回退「仅首层」(team_down_max_level=1):09-17 的「向下无限层(=0)」在生产触发 bug——订单40(XS2026****,买家推荐人 R=990224 的下级链 990231→990232 恰 2 层深)的向下奖被错发到第 2 层(reward_record id=533,down L2,¥1005.80 发给 990232)。根因为配置team_down_max_level=0(无限制→遍历到链底),非代码(RewardEngine::computeV2逻辑本身正确)。修复:生产UPDATE config_param SET team_down_max_level='1', team_up_max_level='0'(向上维持无限制、靠team_down_min_amount=0.01过滤截断深碎额;向下封顶第 1 层)。订单40 唯一错误行 533 用PointEngine::rewardAccelRevoke(533)单笔冲正(六落点成对回滚,status 2→3),系统范围 down L≥2 且 status=2 的 team 行 = 0(无需批量冲正)。当前生产口径:向下team_down_max_level=1(仅第1层)、向上team_up_max_level=0(无限制);§5.2/§5.4 同步校正。 文中 ★ 标记处为已拍板最终口径(含依据与判定日期),未标记者为原《模式总结》口径。
1. 积分体系(共六类,分属 6 个独立账户池)
| 积分种类 | 来源 | 入账时间点 | 其他说明 |
|---|---|---|---|
消费积分 consume_point |
① 礼包区:零售价 × 让利比 × 5;② 非礼包区:零售价 × 让利比 × 5 × 0.5;③ 锁仓积分解锁 |
订单完成 | 转为专属红包时先扣 6%(不论动/静) |
兑换积分 exchange_point |
非礼包区订单:零售价 × 让利比 × 5 × 0.5 |
订单完成 | 仅非礼包区产生,礼包区不产生 |
锁仓积分 lock_point |
后台拨放(非订单自动产生) | 后台操作 | 按每天 0.2% 解锁为消费积分 |
专属红包 red_packet |
消费积分(动/静)释放 + 分红 | 释放/发放时 | 链内上下互转 0.1% 手续费 |
兑换权益 exchange_equity ★ |
兑换积分释放 | 释放时 | 转出需预留审核表单,后台处理;流水写 exchange_equity_record |
积分余额 balance_point ★ |
① 第三方入账(外部系统推送,type=7);② 专属红包 ↔ 积分余额互转(type=5) |
后台操作 / 互转时 | 与专属红包互转 0 手续费;point_record.point_type=4;独立于兑换积分(股票兑换 D3 仍走 exchange_point) |
关键结论:旧的「四池」表述(消费/兑换/锁仓/锁仓已解冻)错误。正确为六类账户;其中「锁仓已解冻
lock_released」只是member上的一个累计计数列(对账校验 + 恒等式lock_point + lock_released = 累计拨发总量),不是一个池 —— 锁仓解锁后直接进入消费积分。
★2026-09-19 修正:lock_point是「当前锁仓余额」(解冻时同步扣减),故 可解冻剩余 =lock_point。旧表述「可解冻剩余 =lock_point − lock_released」属双扣,已于本次修正(详见 §4.1)。
2. 总览:一笔订单触发的积分/资金流向
订单完成(礼包区 或 非礼包区)
│
▼
积 分 入 账(阶段 A,实时)
├─ 礼包区订单 :消费积分 += 零售价 × 让利比 × 5
└─ 非礼包区订单:消费积分 += 零售价 × 让利比 × 5 × 0.5
兑换积分 += 零售价 × 让利比 × 5 × 0.5
(锁仓积分只由后台拨放,不从订单产生)
═══════════════ 以下为周期性/后台动作 ═══════════════
阶 段 B — 积分释放(活跃值=1 才发生)
├─ 锁仓积分:每天 0.2% 解锁 → 消费积分
├─ 消费积分:静态释放 + 动态加速释放 → 专属红包(扣 6%)
└─ 兑换积分:静态释放 → 兑换权益(转出需审核)
阶 段 C — 动态加速(作用于消费积分、锁仓积分;兑换积分无加速)
├─ 分享加速:礼包区订单金额 10%;线下消费者让利额 10%;线下商家让利额 10%
└─ 团队加速(线① v2 三段式):分享奖 R 本人 10%;向上奖 R 上级链 5%×0.5^(k-1);向下奖 R 下级树 5%×0.5^(d-1)(线②商户线仍为固定 10% pass-up,见 §5.2)
阶 段 D — 分红(消耗消费积分,不足原点烧伤)
├─ V1~V6 会员参与 V1..自身级全部分红池(6/5/4/3/2/1 %)
└─ 每池 5:5 拆分:50% 人头均分 + 50% 消费积分占比 → 专属红包
阶 段 E — 互转与转出(red_packet / 权益流出)
├─ 专属红包链内上下互转:手续费 0.1%
├─ 积分余额 ↔ 专属红包:0 手续费
└─ 兑换权益转出:审核表单,后台处理
一句话:订单完成只入账「消费积分/兑换积分」;锁仓积分靠后台拨放再每天 0.2% 解锁;消费/兑换积分靠「活跃值=1 的静态释放 + 消费/锁仓的动态加速」进入专属红包与兑换权益;分红消耗消费积分、按 5:5 拆到专属红包。
3. 阶段 A — 积分入账(订单完成)
触发:订单完成(礼包区与非礼包区口径不同)。幂等按订单,同一订单不重复入账。
公式(精度 bcmath,中间 6 位、落库 2 位截断):
| 订单区 | 发放项 | 公式 | 落点 |
|---|---|---|---|
礼包区(type=1) |
消费积分 | 零售价 × 让利比 × 5 |
consume_point |
| 非礼包区 | 消费积分 | 零售价 × 让利比 × 5 × 0.5 |
consume_point |
| 非礼包区 | 兑换积分 | 零售价 × 让利比 × 5 × 0.5 |
exchange_point |
- 让利额 =
零售价 × 让利比(让利比来自商品配置,具体基准待确认)。 - 锁仓积分不由订单产生,仅
后台拨放入口写入lock_point。 - 记账:
point_record按point_type(1 消费 / 2 兑换 / 3 锁仓 / 4 积分余额)各记一行,balance_after为该池入账后余额。 - 并发/一致性:事务 +
member行锁FOR UPDATE。
4. 阶段 B — 积分释放(静态 + 动态加速)
释放统一前置:活跃值 = 1(活跃值 的构成——需「看广告签到」广告完整即签到成功)。
4.1 锁仓积分解锁(★2026-09-17 改为事件驱动 · 需求 C)
历史口径(已停用):原
point:thaw定时任务(每日 02:00)按「团队礼包业绩×10% + 上线×2% + 下线×2% ÷10」扫描全表解冻。 现按客户 2026-09-17 需求 C 改为事件驱动:不再是任务计划,而是「购买礼包支付成功 / 普通商品确认收货成功」时即时解冻。
触发点(取代定时任务):
- 礼包支付成功 →
GiftPostPay::handle逐 item 调PointEngine::thawLockEvent(买家, 明细原价, …);基数 B = 订单明细原价order_item.amount(未扣券,客户口径「订单金额」;加速奖 settleItem 仍用扣券后实付,二者不同)。 - 普通商品确认收货 →
member/Order::confirm逐非礼包 item 调thawLockEvent(买家, 让利额, …);基数 B = 让利额SettleBase::itemRebate()。 - 总开关
lock_thaw_event_enable=1时,旧thawLock()定时路径直接 no-op(防双触发);置 0 可回退到定时解冻。
中心 R = 买家直接推荐人(member.recommend_id)。以 R 为中心分三段(★2026-09-19 修正:原「向上 10%」拆为「R 直发 10%」+「向上 1%」):
- ★ 推荐人 R 直发 10%:R 本人一次性拿
share = B × lock_ref_rate(0.10),不沿链递归;R 须为有效会员(status=1且has_gift_purchase=1),否则该笔额度灼烧归平台。 - 向上 1%:R 的上级链(R 的
recommend_path解析出的祖先)第 k 级share = B × lock_up_rate(0.01) × lock_up_decay(0.5)^(k−1),lock_up_max_level=0表示无限级(沿上行链发到链顶)。- 必须是有效会员(
status=1且has_gift_purchase=1);非有效会员则该级额度灼烧归平台、递归继续。
- 必须是有效会员(
- 向下 1%:购买者下级树(沿
recommend_idBFS)第 d 层share = B × lock_down_rate(0.01) × lock_down_decay(0.5)^(d−1),无限递归(每层 ×50% 收敛)。- 该层有效会员之间按剩余可解冻锁仓
lock_point(当前锁仓余额)占比分配(★2026-09-19 修正:原写lock_point − lock_released属双扣——两者同向变动,每解冻 1 单位消耗 2 单位额度 ⇒ 权重偏小、提前终止、lock_point残值永久解冻不出来;实测 990203 授予 1000 → 解冻 630.21 后卡死,残 369.79);非有效会员 / 无可解冻锁仓者不参与(其额度灼烧);lock_down_max_nodes=5000熔断防全站扫描。
- 该层有效会员之间按剩余可解冻锁仓
★ 终止条件:向上 / 向下任一层的 share < 0.01 即停止继续递归(Amount::lt($share,'0.01')),避免无限层产生碎额。灼烧总额记入 point_record 统计、不发给任何会员。
解冻动作(对每位获得者):lock_point↓ + lock_released↑ + consume_point↑,且解冻额 cap 在「剩余可解冻锁仓 = lock_point」(★2026-09-19 修正,原为 lock_point − lock_released),杜绝超发。
记账:锁仓池出 / 消费池入(两行 type=4 锁仓解冻,source='lock_thaw')。
幂等:按 order_id + item_id + source='lock_thaw' 判重(同一订单明细仅解冻一次;接收者为各上下级会员,故不看 user_id)。
★ 数据现状(2026-09-19 更新):生产 12 名会员持有锁仓,累计拨发 8,301,000.00(后台手动拨发
admin/Point::grantLock)。2026-09-19 已完成一次「奖励全量重置 + 按节点时间重放」,锁仓已还原至发放总量并按事件重放解冻。
4.2 消费积分释放 → 专属红包
- 静态释放:活跃值 = 1 且
consume_point > 0。 - 动态加速释放(见阶段 C):分享加速 + 团队加速。
- 释放入
red_packet时先扣 6%(不论动/静释放)。★ 该 6% 的去向见 §4.4。
4.3 兑换积分释放 → 兑换权益
- 静态释放:活跃值 = 1 且
exchange_point > 0。 - 无动态加速。
- 释放入「兑换权益」;转出需审核表单(后台处理)。
4.4 ★ 6% 释放税的去向(2026-09-11 拍板 · 最终口径)
结论:记入「平台税沉淀科目」。
| 项 | 内容 |
|---|---|
| 现行实现 | red_packet_tax_rate='0.06'、red_packet_tax_record='0' ⇒ 6% 直接蒸发:不写 ledger、不写 point_record、不入任何账户、不累加 burn_amount(仅 error_log 留文本) |
| 拍板口径 | ★ 不再蒸发,改为入账留痕 —— 冲正时按全额回补会员(会员不亏),同时把 6% 税额记入平台税沉淀科目 |
| 落地前置(★2026-09-12 已落地) | 表 platform_tax_reserve 已建、config_param.tax_reserve_enable='0' 已写入(默认 0 = 现状,部署即零回归);双线已投产 |
| 承接范围 | 建议一张表统一承接三类同性质的「平台留存」,而非给税单独建表:accel_tax(本 6% 税,沉淀)/ burn_gap(差额烧伤,沉淀)/ revoke_tax(冲正释放,支出) |
| 不可复用 | red_packet_ledger(会员红包账本,混入会污染会员对账);point_record.type 的 1~8 已占满,无「税」语义位 |
★ 数据来源:2026-09-11 正式线只读实测 ——
settlement.red_packet_tax_record='0'、red_packet_tax_rate=0.06; 并已用 #4(u1)逐位验证:actual 999.90→ 扣consume_point999.90 → 入红包 939.91 (999.90×0.06 = 59.994 → 939.906 → 入账 939.91✓),单笔税 59.994 蒸发、两笔合计 119.98。
5. 阶段 C — 动态加速释放
作用对象:消费积分、锁仓积分(两者规则一致);兑换积分无加速。
5.1 分享加速
受益人 = 直接推荐人。金额按三类来源:
- 礼包区订单金额 10%
- 线下消费者让利额 10%
- 线下商家让利额 10%
★ v2 起,分享加速并入团队加速三段式统一计算(
direction=share,中心 R = 买家的推荐人),基数按区分叉(礼包区=实付 / 其他区=让利额),见 §5.2。
5.2 ★ 团队加速(v2 三段式 · 2026-09-13 拍板「逐级递减=各序列内递减」 · 2026-09-14 文档同步)
总开关 team_reward_v2_enable=1(双线已开,2026-09-13 翻转)。v2 以中心 R = 买家的推荐人(非买家本人)为圆心,一次计提产生三段奖励:
| 段 | 受益人 | 公式(B = 计提基数) | 落库指纹(reward_record) |
|---|---|---|---|
① 分享奖 share |
R 本人 | B × team_share_rate(0.10) |
direction=share, direction_level=0 |
② 向上奖 up |
R 的上级链第 k 级 | B × team_up_rate(0.05) × 0.5^(k−1),k ≤ team_up_max_level(0=无限制,沿上行链发到链顶) |
direction=up, direction_level=k |
③ 向下奖 down |
R 的下级树第 d 层(含买家本人,team_down_include_buyer=1;仅有效会员 status=1 且 has_gift_purchase=1 参与,层内等分) |
B × team_down_rate(0.02) × 0.5^(d−1),d ≤ team_down_max_level(1=仅第 1 层(当前生产值);0=无限制为 09-17 历史口径,09-18 已回退为 1,见 ⑨) |
direction=down, direction_level=d |
- 逐级递减(已拍板语义):
team_decay_ratio=0.5—— 向上、向下是两条各自独立的递减序列,各自第 1 级都从 5% 起算(2026-09-14 由 10% 下调)、逐级折半;不跨序列连减(故向上#1与向下#1金额可以相等,属正确表现,勿报 bug)。 - 向下段细节:该层仅「有效会员(status=1 且 has_gift_purchase=1,即买过礼包的用户)」参与分配,且有效会员之间按人头等分(平分)该层额度(
team_down_valid_only=1、team_down_alloc=equal)——需求「向下那层必须是有效会员平分 0.02 的奖励」;非有效会员(未购礼包/账号异常)直接不计入候选集(与全局 valid-user 资格烧伤是两套独立机制:此处「先筛人」,后者「算出发再烧」)。某层有效会员余额不足时该层额度整体蒸发(team_down_zero_pool=vanish),且只影响该层、下一层额度照常(B × rate × 0.5^(d−1));team_down_max_nodes=5000熔断防大树扫描。 - ★实发额门槛(2026-09-17 投产,见 §5.4):上/下行统一按
actual(=should − burn,扣烧伤后真实发放额)严格 >team_down_min_amount(0.01)才落库;actual ≤ 0.01的碎额行(深无限层尾部)直接 skip、不写reward_record。上行原本无任何门槛 → 同步加此 strict actual 门槛;下行原 Q10 仅按 pre-burn 金额 ≥0.01 保留 → 改为按 post-burnactual严格 > 0.01。平台兜底team_down_min_amount=0.01。 - 计提基数 B 按区分叉:礼包区订单 = 订单实付(
SettleBase::itemPayAmount());其他区订单 = 让利额(itemRebate())。非礼包入口已放开(accel_nongift_enable=1,2026-09-13 B 方案双线投产):实时钩子在确认收货(member/Order::confirm),兜底走reward:settle非礼包段(按status∈(4,5)扫描、不看日期)。 - 两阶段入账:计提写
reward_record(status=1)只记账;真正入账(扣消费积分 → 入专属红包,扣 6% 税、差额烧伤)由 T6fund:payout执行。★2026-09-14 起计提后立即入账:礼包=支付成功时、其他=确认收货时,在实时钩子内同步调用payRewards()(客户口径「支付后/确认收货后立即执行」),fund:payout(每日 04:00)转为兜底批处理 —— 见 §11「计提 ≠ 到账」与 §4.4。 - 级数提示:v2 中心是 R 而非买家本人 ⇒ 同一订单的向上链可能比旧口径少一级(旧口径沿买家链上行)。
⚠️ 旧表述作废三处(保留作历史对照,勿再据其对账):
- 「每一级固定 10%、非几何衰减、单向 pass-up、封顶 5 级」= v1 口径(沿买家
recommend_path上行),已被 v2 取代(2026-09-13 开关翻转)。历史 v1 行的指纹:direction=''且direction_level=0。- 「每一级拿下一级 50%」=
0.5^d几何衰减 —— 曾于 2026-09-06 弃用,现以「各序列内逐级折半」的形式成为 v2 现行口径(team_decay_ratio=0.5)。- 「向下 10% 当前无此机制」—— 已实现(v2 向下奖),不再是待确认项。
★ 商户线(2026-09-10 增补,团队加速升级为「双线」): 线①(购买者线,
line=1)= 上文 v2 三段式; 线②(商户线,line=2)= 以「商户绑定的 C 端会员(merchant.member_id)」为源,沿该会员的recommend_path上行, 由线下核销让利额(merchant_verify.rebate_amount)触发,仍为每级固定 10%(merchant_line_rate)、单向 pass-up、封顶 5 级(独立计算computeMerchantLine(),不随 v2 三段式变化),受merchant_line_enable控制。 商户未绑定会员 ⇒ 线②无源、不计提。回退:merchant_line_enable=0即一键退回单线(线①不受影响)。
旧版「反加速 recommend(平台拨付招募人 × 0.20)」为错误机制,已删除。正确体系里不存在平台
user_id=0出资的反加速奖。 (配置键recommend_funded_by_platform已全项目无读取方,仅历史reward_record留有recommend记录供后台只读展示。)
每条加速记账:写 point_record(/reward_record)记录 should_amount、actual_amount、batch_no(幂等),不直接触碰余额 cap。
5.3 ★ 有效用户资格(礼包购买门槛 · 2026-09-15 投产)
结论:奖励仅对「有效用户」发放;未买过礼包的账号,其应得奖励全额烧伤归平台。
| 项 | 内容 |
|---|---|
| 有效用户定义 | member.has_gift_purchase = 1(买过礼包)且 member.status = 1(账号正常) |
| 不资格后果 | 即使账号 status=1 正常,只要 has_gift_purchase = 0,其应得「积分入账 / 加速奖」一律不发放 → 全额烧伤归平台(不入账、不补发、不写会员流水) |
| 置标时机 | 礼包支付成功(GiftPostPay::handle)在积分发放 / 加速奖计提前置 has_gift_purchase = 1 |
| 存量补标 | 迁移脚本对历史已购礼包会员补 has_gift_purchase = 1;未购者保持 0(即不资格) |
| 判定入口 | PointEngine::isValidUser()(积分入账 / 加速奖资格闸门);RewardEngine 加速奖中心 R 的资格判定复用该字段 |
| 与「余额烧伤」的区别 | 两套独立闸门:有效用户门槛看 has_gift_purchase(买没买礼包);余额烧伤看 consume_point 余额是否充足(见 §4.4 / §6.1)。前者不通过 ⇒ 整笔不发放;后者不通过 ⇒ 该笔差额蒸发 |
| 作用域 | 仅影响「奖励发放」侧;不影响订单本身、不影响普通购买 / 支付流程 |
★ 数据实况(2026-09-15 正式线只读实测):存量会员 33 人,有效用户(
has_gift_purchase=1)4 人、不资格 29 人;资格闸门 + 迁移补标已双线投产,8/8 只读校验通过(迁移前后计数一致、无资格会员的奖励行数为 0)。
5.4 ★ 团队加速「实发>0.01 才记录」+ 向下仅首层(2026-09-17 投产 / 2026-09-18 向下回退封顶第 1 层)
结论:团队加速上行保持无限制层数、下行(09-18 起)封顶第 1 层;每一笔奖励按「实发金额 actual」严格 > 0.01 才落库;≤0.01 的碎额不写 reward_record。
| 项 | 原口径(2026-09-16 及之前) | 新口径(2026-09-17 起) | 配置键 |
|---|---|---|---|
| 向上层数 | team_up_max_level=0(已无限制) |
不变,仍=0(沿上行链发到链顶) | team_up_max_level |
| 向下层数 | team_down_max_level=1(仅第 1 层) |
=1(仅第 1 层,09-18 回退当前生产值;原 09-17 曾=0 无限制已废弃) | team_down_max_level |
| 上行落库门槛 | 无门槛(深链尾部碎额也会落行) | actual > team_down_min_amount(0.01) 才落库 |
team_down_min_amount(上行复用) |
| 下行落库门槛 | amount ≥ 0.01 保留(pre-burn,Q10) |
actual > 0.01 才落库(post-burn,strict) |
team_down_min_amount |
- 层数财务安全:向上
0.5折半使无限层总额收敛到rate/(1−0.5)=10%基数;下行 09-18 起仅第 1 层(不遍历深树),扫描量极小,原「无限层收敛」仅适用于上行;team_down_max_nodes=5000仍作 BFS 熔断保险(实际不再触发)。 actual定义:RewardEngine::makeRow()产出actual = should − burn(burn=不资格全额烧伤 / 合格按burn_rate烧伤),截断到 2 位小数。门槛判定统一用actual,不是should——即烧伤后的真实发放额。- 代码落点(
backend/app/service/settlement/RewardEngine.php::computeV2):- 上行
foreach makeRow循环内加:if ($uid !== PLATFORM_UID && Amount::gt($minAmt,'0') && Amount::lte($r['actual'], $minAmt)) continue; - 下行
downRow()改为先makeRow得actual,逐行:if ($uid !== PLATFORM_UID && Amount::gt($minAmt,'0') && Amount::lte($r['actual'], $minAmt)) continue;(原按 pre-burn$amount且lt保留 → 改为 post-burnactual严格lte跳过)。
- 上行
- 生产只读探针(零落库)验证(09-17 口径,历史对照):基数 1000 → 上行 112 笔 / 下行 190 笔 / 向下最大层=10(原封顶 1,证 09-17 无限层生效)/ 上·下行
actual ≤ 0.01碎额行均=0;基数 0.01 → 上·下行全被门槛过滤(0 笔)。注意:此探针是在team_down_max_level=0(无限层)下跑的 09-17 读数;09-18 回退=1后下行仅第 1 层,向下笔数回落到「每层有效会员等分」量级,不再有 10 层深扫描。门槛过滤逻辑本身不变。 - 幂等/重放影响:本口径是
RewardEngine::computeV2的运行期行为,重放(见xshop-prod-reward-resetSkill 的 Step 3)读取的是config_param库值(team_down_max_level=1、team_up_max_level=0、team_down_min_amount=0.01),故重放后线上数据即落在此口径下,无需额外改造。
6. 阶段 D — 分红
触发:按日计提(T+1),消耗消费积分。
6.1 分红前提与消耗
- 分红消耗消费积分余额(扣减顺序:先释放、后分红)。
- 消费积分不足时烧伤,原点烧伤(该会员该期分红归零)。
6.2 分红池与等级
- 分红池来源 = 全网礼包专区流水,按各级分红率计提:V1=6% / V2=5% / V3=4% / V4=3% / V5=2% / V6=1%。
- 叠加规则:V2 参与 V1+V2,V3 参与 V1–V3,…,V6 参与 V1–V6 全部池。叠加为每个等级都参与其自身及以下全部池(不是仅 V5+)。
- 各等级累计分红率:V1=6%、V2=11%、V3=15%、V4=18%、V5=20%、V6=21%。
6.3 池内 5:5 拆分
每个分红池总金额:
- 50% 按参与用户人头均分(身份均分)。
- 50% 按用户剩余「消费积分」占比加权分配(旧版误写为「兑换积分」,实为消费积分)。
- 守恒:身份半 + 积分半 = 池总额;逐人末位吸收舍入 residual。
6.4 入账
分红入 red_packet(专属红包)。记账与幂等沿用 batch_no = dividend:{source}:{date}。
7. 会员级别(V1–V6)
| 级别 | 晋升条件(自动) | 参与分红池 | 累计分红率 |
|---|---|---|---|
| 普通会员 | 注册即是 | — | — |
| 有效会员 | 有效消费 > 0 | — | — |
| V1 品牌推广员 | 有效会员 + 亚网体团队总业绩 ≥ 10 万 | V1 | 6% |
| V2 品牌业务合伙人 | 有效会员 + 亚网体团队总业绩 ≥ 30 万 | V1–V2 | 11% |
| V3 品牌拓展合伙人 | ≥ 100 万 | V1–V3 | 15% |
| V4 品牌共建合伙人 | ≥ 500 万 | V1–V4 | 18% |
| V5 品牌合伙人 | ≥ 1000 万 | V1–V5 | 20% |
| V6 项目合伙人(隐藏) | 无自动晋升,仅管理员后台手动指定 | V1–V6 | 21% |
- V6 隐藏:前台显示 V5;账户信息/操作记录仅管理员可见。
- 旧版「V6 未启用、回退 V5、忘原级别」等错误描述已删除:V6 为正式存在的隐藏级别,参与全池 = 21%。
7.1 ★ 业绩口径与阈值(2026-09-11 P0 批次已上线 · 最终口径)
① 「亚网体团队总业绩」= 非礼包让利额,沿推荐链含自身累加。
| 来源 | 字段 |
|---|---|
| 线上 | sales_order.rebate_amount |
| 线下 | merchant_verify.rebate_amount |
⚠️ 旧口径是「礼包订单实付」,两者量级差约 5 倍 ⇒ 同为 10 万门槛,新口径的达成难度约为旧的 5 倍。 这是业务有意的口径收紧,不是 bug。
② 阈值经 config_param 提供;键名语义 = 「晋升到 V(N+1) 的门槛」,本次只上移取值、不改键名。
| 键名 | 取值 | 语义 |
|---|---|---|
level_v0_threshold |
100,000(10 万) | ≥10 万 → V1 |
level_v1_threshold |
300,000(30 万) | ≥30 万 → V2 |
level_v2_threshold |
1,000,000(100 万) | ≥100 万 → V3 |
level_v3_threshold |
5,000,000(500 万) | ≥500 万 → V4 |
level_v4_threshold |
10,000,000(1000 万) | ≥1000 万 → V5 |
level_v5_threshold |
10,000,000 | 保留但不再参与自动晋升(V6 改为后台手动指定) |
③ 前置条件:V1 及以上须为有效会员(累计有效消费 > 0,口径 = Σ 扣券后实付)。
④ 引擎行为:仅升不降;仅 status=1 会员自动晋升;存量 V6 会员不受影响。
⑤ 分工提醒:「晋升业绩」用非礼包让利额;「加速奖(v2 三段式,见 §5.2)」的基数按区分叉:
礼包区订单 = 订单实付、其他区订单 = 让利额(accel_nongift_enable=1 后非礼包单也计提)——
礼包区订单的加速奖基数与晋升业绩口径量级差约 5 倍,勿混用。
8. 代理制度(线下结算,红利入专属红包/账户)
| 代理级别 | 考核条件 | 权益 1(区域收益) | 权益 2(单件补贴,入专属红包) |
|---|---|---|---|
| 工作室 | 团队总业绩 ≥ 50 万 且 线下消费让利总额 ≥ 50 万,可叠加多组 | 每组 1 万元扶持经费,多组达标可叠加(后台拨放,不扣消费积分) | — |
| 区县代理 | 月度自动统计辖区业绩与让利 | 辖区内线下消费让利总额 6% | 单件利润达标 6 元及以上 → 单件计提 3 元 |
| 市级代理 | 同上 | 辖区让利总额 2% | 单件计提 2 元 |
| 省级代理 | 同上 | 辖区让利总额 1% | 单件计提 1 元 |
权益 2 需扣消费积分、补贴到专属红包(工作室为后台拨放、不扣消费积分)。
9. 互转与转出(red_packet / 权益流向)
- 专属红包链内上下互转:手续费 0.1%;同一链内(上下级关系)可转;事务 + 双方
FOR UPDATE行锁;写red_packet_ledger。 - 积分余额 ↔ 专属红包:0 手续费(积分余额来自第三方后台入账)。
- 兑换权益转出:预留审核表单,后台处理(非实时直接提现)。
- 旧版单一的「提现
WithdrawEngine」可作为专属红包提现的具体实现保留,但它并非唯一流出通道。
10. 数据 / 对账保障
- 六类账户池(
consume_point/exchange_point/lock_point/red_packet/ 兑换权益 / 积分余额)独立落member。 - 所有变动写
point_record/red_packet_ledger,balance_after为对应池余额 → 对账中心逐账户校验「末笔流水余额 = 当前余额」。 - ★ 平台侧留存(非会员账户):6% 释放税、差额烧伤、冲正释放税额 → 见 §4.4,
已统一落
platform_tax_reserve台账(★2026-09-12 已建表并双线投产,开关tax_reserve_enable默认 0)。它与「会员账户池」性质不同: 不属于任何会员,故不可混入red_packet_ledger(会污染会员对账)。 - ⚠️ 精度陷阱(2026-09-11 实测,复刻金额逻辑前必读):
Amount::round()是截断 (bcadd($a,'0',$s),bcmath 向零舍入)而非四舍五入;且allocate()采用末位吸收 (uid 升序,最后一个吃残差)⇒ 末位 uid 系统性多拿(同权同级七日差 2.88 元,上界≈人数×0.01/池/半)。 复刻须用 Decimal + ROUND_DOWN 并逐人校准。 - 精度统一
bcmath(SCALE=6 中间算、落库 2 位截断);并发用行锁 + 余额 cap 防超发;无 Redis 环境用job_queue+schedule_lock表实现自研队列/分布式锁。
11. 待确认清单(逐项标注:已确认 / 已实现 / 仍留白)
| # | 模块 | 待确认项 | 当前口径 | 状态(2026-09-11) |
|---|---|---|---|---|
| 1 | 入账 | 「让利比」的商品配置基准 | 让利额 = 零售价 × 让利比;礼包区 ×5,非礼包区 ×5×0.5 双池 | 仍留白 |
| 2 | 释放 | 「活跃值 = 1」的构成(看广告完成) | 仅约定活跃值=1 | 仍留白 |
| 3 | 释放 | 消费积分转专属红包扣 6% 的征收方 | 按 6% 扣 | 已确认:记入平台税沉淀科目(见 §4.4) |
| 4 | 团队加速 | 团队加速的比例与方向 | v2 三段式:分享奖 10% + 向上奖 5%×0.5^(k−1) + 向下奖 5%×0.5^(d−1)(各序列内逐级折半,中心 R = 买家推荐人;2026-09-14 第 1 级 10%→5%);线②商户线仍固定 10% pass-up | 已确认且已投产(见 §5.2;2026-09-13 拍板「各序列内递减」并翻转开关,2026-09-14 正式线 v2 全量重置落账 + 比例下调) |
| 5 | 分红 | 分红消耗消费积分的额度 | 按分红额消耗,不足原点烧伤 | 已实现;「身份半是否受余额约束」仍留白(见下) |
| 6 | 等级 | 「亚网体团队总业绩」的统计口径 | 非礼包让利额,沿推荐链含自身(线上 sales_order.rebate_amount + 线下 merchant_verify.rebate_amount) |
已确认(见 §7.1) |
| 7 | 字段 | 「兑换权益」「积分余额」两个新池的落库字段名 | exchange_equity / balance_point(2026-09-12 确认) |
已确认(积分余额池已双线投产;见 §1) |
| 8 | 代理 | 工作室「多组可叠加」的组上限、区县辖区归属 | 按需求原文 | 仍留白 |
| 9 | 冲正 | 订单退款/取消后的资金冲正 | — | 已拍板且已投产(见 §12;2026-09-12 P0–P4 双线完工) |
★ 2026-09-11 新增留白(本轮挖掘出的新问题):
- 分红「身份半」是否受消费积分余额约束 —— 实测烧伤率 43.69%,且逐分等于 29 名零余额会员的「身份半」。 若定为「余额校验只作用于积分半」⇒ 烧伤归零、平台零成本(已离线推演)。待拍板。
- 差额烧伤是否并入「平台税沉淀」 —— 现行是直接蒸发(不归平台沉淀账户、不入任何池、不写流水,
仅累加
reward_record.burn_amount)。§4.4 建议与 6% 税并入同一台账,但本轮仅 6% 税已拍板,烧伤是否沉淀待定。 point:thaw(锁仓解冻)数值变化是否接受 —— 修ancestorIds()后上线链会多算正确的一层, 解冻数值变准(两线lock_point > 0当前 0 人,故当前实际零影响)。
★ 2026-09-12 新增留白(正式线实测):
- 加速奖「零行计提不留痕」 ——
RewardEngine::compute()在买家无上级链(recommend_path为空)时返回空数组,persistRows([])直接返回 0、不写任何batch_no幂等痕迹 ⇒ 若下单 / 支付时买家尚未接入推荐链, 该单永久无加速奖且无自动补算(实测正式线order#2 / #3 / #8三单零reward_record)。 叠加reward:settle因reward_settle_offset_days=0只扫当天 00:00–00:30(兜底实际不生效)。 「是否补计提 / 是否置offset=1/ 是否改为下单即时发放」待拍板。 - 加速奖「计提 ≠ 到账」是两阶段 —— 下单即时写
reward_record(status=1)(不碰余额), 真正入账(consume_point → red_packet,扣 6% 税)由 T6fund:payout每日 04:00 执行 ⇒ 当日计提的奖励次日才在会员专属红包可见(见 §12.2)。若业务要求「下单即时到账」需另行改造。
已确认的固定决策:旧版大量假设(lock_ratio=0.4 订单锁仓、反加速平台出资 0.20、分红按兑换积分加权、V6 未启用等)已全部纠正为《模式总结》口径;锁仓积分仅后台拨放、订单不锁仓。
12. ★ 订单冲正(退款 / 取消后的资金收回)· 2026-09-11 拍板
依据:
outputs/q20-revoke-skeleton/Q20订单冲正骨架设计方案.html(13 表 / 9 章)。 全部数字取自正式线只读实测(2026-09-11),未写入任何数据。
12.1 为什么需要(现状缺口)
| 入口 | 当前行为 | 资金冲正 |
|---|---|---|
admin/Order::close |
status=5 + settle_invalid=1(reason=admin_close) |
无 |
merchant/Order::refund |
源码注释原文「仅状态标记,资金侧由平台结算链路处理」—— 而平台侧并不存在该逻辑 | 无 |
api/Order::cancel |
status=6 + settle_invalid=1(reason=member_cancel);支付成功由 OrderPostPayService::onPaid 清 settle_invalid=0(对称 payConfirm),「已付款却被剔除」隐患已消除 |
无 |
admin/Order::payConfirm |
清 settle_invalid=0,走 OrderPostPayService::onPaid |
—(反向:重新激活) |
⇒ settle_invalid 只解决「未结算订单的排除」;已发放到会员账上的积分与红包,当前无任何机制可以收回。
12.2 ★ 颠覆性前提:加速奖不是「平台发钱」,是「会员积分变现 + 6% 税」
T3 计提(RewardEngine::settleItem)→ 写 reward_record(status=1),★ 完全不碰任何余额
T6 发放(fund:payout,每日 04:00)→ PointEngine::rewardAccelTransfer()
实发 = min(应发, 会员 consume_point 余额)
扣 member.consume_point -= 实发
税 = 实发 × 6% ← 直接蒸发(去向见 §4.4,已拍板改为入账)
收 member.red_packet += 实发 × 94%
写 point_record type=6(负数)+ red_packet_ledger(change_type='reward')
差额(积分不足)→ 蒸发,累加 reward_record.burn_amount
→ reward_record.status = 2
⇒ 业务定性:退款冲正 = 「撤销一次积分变现」,不是「追回平台给出去的钱」。这决定了下文全部口径。
★ 冲正必须「成对回滚」的 6 个落点(少一个账就不平):
member.consume_point ・ member.red_packet ・ point_record(type=6) ・ red_packet_ledger ・
reward_record.status ・ sales_order.settle_invalid(+ 反向流水)。
12.3 ★ 五项拍板口径
| 编号 | 问题 | 拍板结论 |
|---|---|---|
| Q20-1 | 冲正方案 | C 分级:未发放(status=1)立即撤回;已发放(status=2)挂人工审批后执行 |
| Q20-2 | 余额不足时 | 全额不扣,粒度 = 整笔跳过(含积分侧也不动) |
| Q20-3 | 6% 税归属 | 记入平台税沉淀科目(全额回补会员 + 税额入账留痕),见 §4.4 |
| Q20-4 | 业绩与晋升 | 不回退 |
| Q20-5 | 分红追溯 | 只对未发放批次日(fund:payout 04:00 一过即不可逆) |
12.4 ★★ Q20-2 必须「整笔原子」(反直觉点,写代码前必读)
「全额不扣」不等于「只跳过扣红包那一步」。若只跳红包、却把积分回补给会员,
会留下 「积分已还、红包未收」的不守恒中间态 ⇒ 会员净多占 actual 积分 + 94%×actual 红包,平台白亏 94%。
⇒ 正确做法:任一落点不满足 ⇒ 该笔冲正整体不执行(等价于「冲正未发生」,账自洽)。
★ 作用域推论(好消息):C 分级下自动路径只处理 status=1(翻状态、零资金动作)⇒ 永远遇不到余额不足;
Q20-2 实际只在「人工审批执行 status=2 批次」时充当安全阀(余额不足 ⇒ 拒绝执行并提示,不打负数、不留欠账)
⇒ 整条自动路径可做到「零余额风险」。
12.5 存量面(2026-09-11 只读实测)
| 核查项 | 实测 |
|---|---|
settle_invalid=1 的订单 |
0 单(13 单全 0,reason 全空) |
order_refund 表 |
空表(0 行) |
sales_order.status 分布 |
仅 1(待付,2) / 2(已付,9) / 4(完成,2);不存在 5 / 6 / 9 |
| 唯一「不可逆面」 | reward_record id 21 / 22(#4 → u1 共 1,999.80,已入红包 1,879.82,税 119.98 已蒸发) |
status=1 待撤回 |
12 行 / 958.80(翻状态即可,零资金动作) |
★ 2026-09-12 更新:上表
status=1的 12 行已于 09-12 04:00 由fund:payout正常发放(status→2、已入会员红包), 故其不再属于「待撤回」面;「唯一不可逆面」reward_record id 21 / 22结论仍成立。★ 2026-09-14 更新:正式线 14 单 48 行 v1 奖励已按 v2 全量重置(余额回滚 → 删历史行 → v2 重计提 →
fund:payout放款 60 行 ¥26,094.82、burned=0)。 上表为 09-11 时点快照;「不可逆面reward_record id 21/22」行已随重置删除(全量备份于xydshop.reward_record_bak/red_packet_ledger_bak/point_record_bak)。
⇒ 零历史包袱,不需要任何历史补扣。
12.6 落地路径(★2026-09-12 P0–P4 全部完工 · 双线投产)
| 阶段 | 交付 | 关键点 |
|---|---|---|
| P0 | 平台税沉淀科目 platform_tax_reserve |
新前置件(因 Q20-3);开关 tax_reserve_enable 默认 0 |
| P1 | RewardEngine::revokeByOrder() 撤回未发放 |
只处理 status=1:翻 status=3(已冲正) + 写 revoked_at/reason;不碰任何余额 |
| P2 | PointEngine::rewardAccelRevoke() 六落点回滚 |
+ 反向流水;受 order_revoke_enable 控(默认 0) |
| P3 | OrderRevokeCommand + 接入点 |
接入 admin/Order::close、merchant/Order::refund;带 --dry-run |
| P4 | 只读探针 + 双线部署 | 必测反向对照 + 守恒断言(consume_point 回补额 + red_packet 扣回额 + 税 = 原 actual) |
★ 上述 P0–P4 已于 2026-09-12 全部完工并双线投产:
platform_tax_reserve建表、order:revoke命令(含--dry-run)、 六落点成对回滚(consume_point/red_packet/point_record(type=6)/red_packet_ledger/reward_record.status/ 反向流水)、 接入admin/Order::close+merchant/Order::refund;两个开关tax_reserve_enable/order_revoke_enable均默认 0(零行为变更)。 P1「撤回未发放(status=1)」为零资金动作,不受开关约束,已在线生效。
★ 事务边界约束:冲正不能放在 merchant/Order::refund 的同一事务里做「跨商户」操作 ——
奖励收款人是买家的上线,可能属于完全无关的商户。必须按订单维度执行、各自成事务、可单独重试。
★ 遗留技术点(已完成):tax_reserve_enable / order_revoke_enable 已加入 admin/Config::IMMEDIATE_KEYS(2026-09-12),后台改开关即时生效。