fix(fsgx): 直推积分奖励链路校验(问题2)

- 买家直推人非分销员时中断直推级差链,避免祖先越级拿 reward_direct
- 同步更新 fsgx-issues-0330 文档问题2用例说明

Made-with: Cursor
This commit is contained in:
apple
2026-03-31 15:25:48 +08:00
parent 583105e23a
commit 1c0cf5204f
2 changed files with 65 additions and 30 deletions

View File

@@ -1,9 +1,19 @@
# 测试问题 # 测试问题
## 分销员的**直推积分奖励**问题 ## 分销员的**直推积分奖励**问题1
- **已检查**当前用户UID=30推荐UID=34推荐UID=31现在UID=31购买的报单商品订单 - **已检查**当前用户UID=30推荐UID=34推荐UID=31现在UID=31购买的报单商品订单
检查UID=30创客是否有直推积分奖励如果有是不对的原因UID=34UID=30都是创客分销员一个订单在同一个级别的分销员只能获得一次直推积分奖励且是直推关系。 检查UID=30创客是否有直推积分奖励如果有是不对的原因UID=34UID=30都是创客分销员一个订单在同一个级别的分销员只能获得一次直推积分奖励且是直推关系。
## 分销员的**直推积分奖励**问题2
- case1: 当前用户UID=2推荐UID=46推荐UID=47现在UID=47购买的报单商品订单情况下目前数据库中有订单和用户数据验证如下
检查UID=46是创客
UID=2是否有直推积分奖励如果没有是不对的原因UID=2分销等级>UID=46,是应该获得直推积分奖励的差额部分,使用**直推积分奖励**的递归计算方法,逐一查询上级的直推积分奖励**直到最高分销等级结束**
检查UID=46还不是创客
UID=2是否有直推积分奖励如果有是不对的原因不是直推关系
- case2: 当前用户UID=46推荐UID=47推荐UID=48现在UID=48购买的报单商品订单情况下目前数据库中有订单和用户数据验证如下
检查UID=46应该没有直推积分奖励才对因为UID=46不是UID=48的直接推荐人
- **直推积分奖励**落库的时候一定要检查直推关系。
## 新增**伞下积分奖励**开关功能 ## 新增**伞下积分奖励**开关功能
- **已修复**新增伞下积分奖励开关功能,默认是关闭的 - **已修复**新增伞下积分奖励开关功能,默认是关闭的
@@ -12,7 +22,7 @@
## 我的资产页面pages/assets/index ## 我的资产页面pages/assets/index
- **已修复**积分明细跳转路径修改为pages/users/user_integral_detail/index - **已修复**积分明细跳转路径修改为pages/users/user_integral_detail/index
- 顶部navbar改成和pages/users/user_spread_user/index页面一样的样式同时美化页面其他部分的样式 - **已修复**顶部navbar改成和pages/users/user_spread_user/index页面一样的样式同时美化页面其他部分的样式
## 佣金状态页面pages/queue/status ## 佣金状态页面pages/queue/status
- 顶部navbar改成和pages/users/user_spread_user/index页面一样的样式同时美化页面其他部分的样式 - **已修复**顶部navbar改成和pages/users/user_spread_user/index页面一样的样式同时美化页面其他部分的样式

View File

@@ -82,14 +82,20 @@ class PointsRewardServices extends BaseServices
* max(0, 自身 direct_reward_points - 链中已见最高 direct_reward_points) * qty * max(0, 自身 direct_reward_points - 链中已见最高 direct_reward_points) * qty
* 非分销员grade=0跳过但继续向上传递$lowerDirectReward 不变。 * 非分销员grade=0跳过但继续向上传递$lowerDirectReward 不变。
* *
* @param int $uid 当前被奖励用户 * 直推关系约束($directCascadeActive
* @param int $fromUid 触发方(下级)用户 ID * 当买家直接推荐人depth=0不是分销员grade=0直推级差链终止
* @param string $orderId 来源订单号 * 其所有上级祖先不得获得 reward_direct不存在直推关系
* @param int $lowerDirectReward 链中已被下级拿走的最高 direct_reward_points级差下限 * 伞下奖励reward_umbrella不受此约束仍按自身开关独立发放。
* @param int $depth 递归深度(防止无限递归) *
* @param int $orderDbId 订单表主键 id * @param int $uid 当前被奖励用户
* @param array $preUpgradeLevels 升级前各用户的 agent_level 快照 [uid => level_id]B2 * @param int $fromUid 触发方(下级)用户 ID
* @param int $qty 报单商品数量积分按数量倍乘B3 * @param string $orderId 来源订单号
* @param int $lowerDirectReward 链中已被下级拿走的最高 direct_reward_points级差下限
* @param int $depth 递归深度(防止无限递归)
* @param int $orderDbId 订单表主键 id
* @param array $preUpgradeLevels 升级前各用户的 agent_level 快照 [uid => level_id]B2
* @param int $qty 报单商品数量积分按数量倍乘B3
* @param bool $directCascadeActive 直推级差链是否仍然有效
*/ */
private function propagateReward( private function propagateReward(
int $uid, int $uid,
@@ -99,7 +105,8 @@ class PointsRewardServices extends BaseServices
int $depth = 0, int $depth = 0,
int $orderDbId = 0, int $orderDbId = 0,
array $preUpgradeLevels = [], array $preUpgradeLevels = [],
int $qty = 1 int $qty = 1,
bool $directCascadeActive = true
): void { ): void {
if ($depth >= 10 || $uid <= 0) { if ($depth >= 10 || $uid <= 0) {
return; return;
@@ -117,33 +124,50 @@ class PointsRewardServices extends BaseServices
$grade = $this->agentLevelServices->getGradeByLevelId($agentLevelId); $grade = $this->agentLevelServices->getGradeByLevelId($agentLevelId);
if ($grade === 0) { if ($grade === 0) {
// 非分销员:跳过奖励,继续向上传递$lowerDirectReward 保持不变 // 非分销员:跳过奖励,继续向上传递
// 若当前节点是买家的直接推荐人depth=0直推级差链从此中断
// 上级祖先与买家之间没有直推关系,不应获得 reward_direct
$nextCascadeActive = ($depth === 0) ? false : $directCascadeActive;
if ($user['spread_uid']) { if ($user['spread_uid']) {
$this->propagateReward((int)$user['spread_uid'], $uid, $orderId, $lowerDirectReward, $depth + 1, $orderDbId, $preUpgradeLevels, $qty); $this->propagateReward((int)$user['spread_uid'], $uid, $orderId, $lowerDirectReward, $depth + 1, $orderDbId, $preUpgradeLevels, $qty, $nextCascadeActive);
} }
return; return;
} }
$directReward = $this->agentLevelServices->getDirectRewardPoints($agentLevelId); $directReward = $this->agentLevelServices->getDirectRewardPoints($agentLevelId);
// 级差:本节点只拿超出下级已取走部分的差额,再乘以数量 // 直推级差:仅在直推链有效时发放(买家直接推荐人必须是分销员)
// 间接上级depth>0即非直推父节点受伞下奖励开关控制hjf_umbrella_reward_enable默认关闭 if ($directCascadeActive) {
if ($depth > 0) {
$umbrellaRewardEnable = (int)sys_config('hjf_umbrella_reward_enable', 0);
$actual = $umbrellaRewardEnable ? max(0, $directReward - $lowerDirectReward) * $qty : 0;
} else {
$actual = max(0, $directReward - $lowerDirectReward) * $qty; $actual = max(0, $directReward - $lowerDirectReward) * $qty;
if ($actual > 0) {
$this->grantFrozenPoints(
$uid,
$actual,
$orderId,
'reward_direct',
'直推奖励(级差)' . " x{$qty} - 来源订单 {$orderId}",
$orderDbId
);
}
} }
if ($actual > 0) { // 伞下积分奖励独立逻辑仅对间接上级depth>0生效受开关控制
$this->grantFrozenPoints( // 使用 umbrella_reward_points 平额发放(非级差),各等级独立拿自身额度
$uid, if ($depth > 0) {
$actual, $umbrellaRewardEnable = (int)sys_config('hjf_umbrella_reward_enable', 0);
$orderId, if ($umbrellaRewardEnable) {
'reward_direct', $umbrellaPoints = $this->agentLevelServices->getUmbrellaRewardPoints($agentLevelId);
'直推奖励(级差)' . " x{$qty} - 来源订单 {$orderId}", if ($umbrellaPoints > 0) {
$orderDbId $this->grantFrozenPoints(
); $uid,
$umbrellaPoints * $qty,
$orderId,
'reward_umbrella',
'伞下奖励' . " x{$qty} - 来源订单 {$orderId}",
$orderDbId
);
}
}
} }
// 向上传递时,下限取当前节点与已有下限中的较大值,确保上级只拿增量 // 向上传递时,下限取当前节点与已有下限中的较大值,确保上级只拿增量
@@ -157,7 +181,8 @@ class PointsRewardServices extends BaseServices
$depth + 1, $depth + 1,
$orderDbId, $orderDbId,
$preUpgradeLevels, $preUpgradeLevels,
$qty $qty,
$directCascadeActive
); );
} }
} }