fix(hjf): 保单商品多份购买分润计算全链路修复

- 公排入队:按件数拆分为 N 条独立记录,每条单份金额,逐条触发退款检测
- 周期佣金:位次统计改为按报单商品总件数(cart_num 之和),而非订单数
- 分销等级任务:type 6/7 订单数统计改为按 cart_num 累计保单商品份数
- 推荐返佣与积分奖励:验证 cart_num 倍乘逻辑正确

Made-with: Cursor
This commit is contained in:
panchengyong
2026-04-06 02:40:01 +08:00
parent fb89fbbacb
commit 364d5333d7
4 changed files with 93 additions and 42 deletions

View File

@@ -1,4 +1,11 @@
# 测试问题 # 测试问题
## 提现页面pages/users/user_cash/index ## 提现页面pages/users/user_cash/index
- 选择支付宝提现点击“立即提现”提交后跳转到pages/users/user_spread_money/index?type=1 - **已修复**选择支付宝提现点击“立即提现”提交后跳转到pages/users/user_spread_money/index?type=1
## 保单商品一次购买多份下的分润计算
- **已修复**推荐返佣按照一次购买多单的分润计算如购买5份则返佣5份而不是1份。
- **已修复**积分奖励同上
- **已修复**分销等级任务中订单数统计改为按购买保单商品份数计算如购买5份保单商品则订单数统计为5份而不是1份。
- **已修复**公排入队按件数拆分为 N 条独立记录PRD §3.1.2),每条单份金额,逐条触发退款检测
- **已修复**周期佣金位次统计改为按报单商品总件数(而非订单数),确保跨订单轮巡位次连续

View File

@@ -34,11 +34,44 @@ class HjfOrderPayJob extends BaseJobs
public function doJob(int $uid, string $orderId, float $amount = 3600.00): bool public function doJob(int $uid, string $orderId, float $amount = 3600.00): bool
{ {
// 先查订单与购物车,计算报单商品总件数(公排入队 + 积分奖励共用)
$orderRow = Db::name('store_order')
->where('order_id', $orderId)
->where('is_queue_goods', 1)
->field('id,uid,is_queue_goods')
->find();
$queueQty = 1;
if ($orderRow) {
try {
$cartRows = Db::name('store_order_cart_info')
->where('oid', (int)$orderRow['id'])
->column('cart_info');
$qtySum = 0;
foreach ($cartRows as $row) {
$item = is_string($row) ? json_decode($row, true) : $row;
if (!empty($item['productInfo']['is_queue_goods'])) {
$qtySum += (int)($item['cart_num'] ?? 1);
}
}
if ($qtySum > 0) {
$queueQty = $qtySum;
}
} catch (\Throwable $qe) {
Log::warning("[HjfOrderPay] 计算报单商品数量异常使用默认值1: " . $qe->getMessage());
}
}
// PRD §3.1.2:一次购买多份时,拆分为多个独立记录分别进入公排池
$unitAmount = $queueQty > 1 ? round($amount / $queueQty, 2) : $amount;
try { try {
/** @var QueuePoolServices $queueServices */ /** @var QueuePoolServices $queueServices */
$queueServices = app()->make(QueuePoolServices::class); $queueServices = app()->make(QueuePoolServices::class);
$queueServices->enqueue($uid, $orderId, $amount); for ($i = 0; $i < $queueQty; $i++) {
Log::info("[HjfOrderPay] 公排入队成功 uid={$uid} orderId={$orderId}"); $subOrderId = $queueQty > 1 ? $orderId . '-' . ($i + 1) : $orderId;
$queueServices->enqueue($uid, $subOrderId, $unitAmount);
}
Log::info("[HjfOrderPay] 公排入队成功 uid={$uid} orderId={$orderId} qty={$queueQty} unitAmount={$unitAmount}");
} catch (ValidateException $e) { } catch (ValidateException $e) {
Log::warning("[HjfOrderPay] 入队被锁,延迟重试 uid={$uid} orderId={$orderId}: " . $e->getMessage()); Log::warning("[HjfOrderPay] 入队被锁,延迟重试 uid={$uid} orderId={$orderId}: " . $e->getMessage());
static::dispatchSece(5, [$uid, $orderId, $amount]); static::dispatchSece(5, [$uid, $orderId, $amount]);
@@ -77,40 +110,15 @@ class HjfOrderPayJob extends BaseJobs
} }
// 等级升级完成后发放积分奖励(确保使用升级后的 agent_level // 等级升级完成后发放积分奖励(确保使用升级后的 agent_level
try { if ($orderRow) {
$orderRow = Db::name('store_order') try {
->where('order_id', $orderId)
->where('is_queue_goods', 1)
->field('id,uid,is_queue_goods')
->find();
if ($orderRow) {
// fsgx B3计算订单中报单商品的总数量积分按数量倍乘
$queueQty = 1;
try {
$cartRows = Db::name('store_order_cart_info')
->where('oid', (int)$orderRow['id'])
->column('cart_info');
$qtySum = 0;
foreach ($cartRows as $row) {
$item = is_string($row) ? json_decode($row, true) : $row;
if (!empty($item['productInfo']['is_queue_goods'])) {
$qtySum += (int)($item['cart_num'] ?? 1);
}
}
if ($qtySum > 0) {
$queueQty = $qtySum;
}
} catch (\Throwable $qe) {
Log::warning("[HjfOrderPay] 计算报单商品数量异常使用默认值1: " . $qe->getMessage());
}
/** @var PointsRewardServices $pointsService */ /** @var PointsRewardServices $pointsService */
$pointsService = app()->make(PointsRewardServices::class); $pointsService = app()->make(PointsRewardServices::class);
$pointsService->reward($uid, $orderId, (int)$orderRow['id'], $preUpgradeLevels, $queueQty); $pointsService->reward($uid, $orderId, (int)$orderRow['id'], $preUpgradeLevels, $queueQty);
Log::info("[HjfOrderPay] 积分奖励发放完成 uid={$uid} orderId={$orderId} qty={$queueQty}"); Log::info("[HjfOrderPay] 积分奖励发放完成 uid={$uid} orderId={$orderId} qty={$queueQty}");
} catch (\Throwable $e) {
Log::error("[HjfOrderPay] 积分奖励发放失败 uid={$uid} orderId={$orderId}: " . $e->getMessage());
} }
} catch (\Throwable $e) {
Log::error("[HjfOrderPay] 积分奖励发放失败 uid={$uid} orderId={$orderId}: " . $e->getMessage());
} }
return true; return true;

View File

@@ -423,7 +423,31 @@ class AgentLevelTaskServices extends BaseServices
} }
/** /**
* 统计直推下级的报单订单数type=6 任务 * 根据订单 ID 列表统计其中报单商品的总件数cart_num 之和
*
* 一笔订单购买 N 份报单商品时 cart_num=N本方法返回所有订单的 N 之和,
* 而非订单行数。与 HjfOrderPayJob / StoreOrderCreateServices 中的 B3/B6 逻辑一致。
*/
private function sumQueueGoodsQty(array $orderIds): int
{
if (empty($orderIds)) {
return 0;
}
$cartRows = Db::name('store_order_cart_info')
->whereIn('oid', $orderIds)
->column('cart_info');
$total = 0;
foreach ($cartRows as $row) {
$item = is_string($row) ? json_decode($row, true) : $row;
if (!empty($item['productInfo']['is_queue_goods'])) {
$total += (int)($item['cart_num'] ?? 1);
}
}
return $total;
}
/**
* 统计直推下级的报单商品总份数type=6 任务)
* *
* @param int $uid 用户 ID * @param int $uid 用户 ID
* @return int * @return int
@@ -437,14 +461,14 @@ class AgentLevelTaskServices extends BaseServices
if (empty($directUids)) { if (empty($directUids)) {
return 0; return 0;
} }
// fsgx B5补充 refund_status 检查,与其他任务类型保持一致,排除已全额退款订单 $orderIds = Db::name('store_order')
return (int)Db::name('store_order')
->whereIn('uid', $directUids) ->whereIn('uid', $directUids)
->where('is_queue_goods', 1) ->where('is_queue_goods', 1)
->where('paid', 1) ->where('paid', 1)
->where('is_del', 0) ->where('is_del', 0)
->whereIn('refund_status', [0, 3]) ->whereIn('refund_status', [0, 3])
->count(); ->column('id');
return $this->sumQueueGoodsQty($orderIds);
} }
/** /**
@@ -492,14 +516,14 @@ class AgentLevelTaskServices extends BaseServices
if ($childGrade >= 2) { if ($childGrade >= 2) {
continue; continue;
} }
// fsgx B5补充 refund_status 检查,排除已全额退款订单 $childOrderIds = Db::name('store_order')
$total += (int)Db::name('store_order')
->where('uid', $child['uid']) ->where('uid', $child['uid'])
->where('is_queue_goods', 1) ->where('is_queue_goods', 1)
->where('paid', 1) ->where('paid', 1)
->where('is_del', 0) ->where('is_del', 0)
->whereIn('refund_status', [0, 3]) ->whereIn('refund_status', [0, 3])
->count(); ->column('id');
$total += $this->sumQueueGoodsQty($childOrderIds);
$total += $this->recursiveUmbrellaCount((int)$child['uid'], $remainDepth - 1); $total += $this->recursiveUmbrellaCount((int)$child['uid'], $remainDepth - 1);
} }
return $total; return $total;

View File

@@ -1028,13 +1028,25 @@ class StoreOrderCreateServices extends BaseServices
return '0'; return '0';
} }
// fsgx B6统计推荐人已完成的报单订单数作为起始位次基准 // fsgx B6统计推荐人已完成的报单商品总件数(非订单数,作为起始位次基准
$completedCount = (int)\think\facade\Db::name('store_order') $completedOrderIds = \think\facade\Db::name('store_order')
->where('spread_uid', $spread_uid) ->where('spread_uid', $spread_uid)
->where('is_queue_goods', 1) ->where('is_queue_goods', 1)
->where('paid', 1) ->where('paid', 1)
->where('is_del', 0) ->where('is_del', 0)
->count(); ->column('id');
$completedCount = 0;
if ($completedOrderIds) {
$completedCartRows = \think\facade\Db::name('store_order_cart_info')
->whereIn('oid', $completedOrderIds)
->column('cart_info');
foreach ($completedCartRows as $ccRow) {
$ccItem = is_string($ccRow) ? json_decode($ccRow, true) : $ccRow;
if (!empty($ccItem['productInfo']['is_queue_goods'])) {
$completedCount += (int)($ccItem['cart_num'] ?? 1);
}
}
}
// fsgx B-2B逐件轮巡每件商品取下一个位次的佣金比例后累加 // fsgx B-2B逐件轮巡每件商品取下一个位次的佣金比例后累加
$total = '0'; $total = '0';