fix(hjf): 保单商品多份购买分润计算全链路修复
- 公排入队:按件数拆分为 N 条独立记录,每条单份金额,逐条触发退款检测 - 周期佣金:位次统计改为按报单商品总件数(cart_num 之和),而非订单数 - 分销等级任务:type 6/7 订单数统计改为按 cart_num 累计保单商品份数 - 推荐返佣与积分奖励:验证 cart_num 倍乘逻辑正确 Made-with: Cursor
This commit is contained in:
@@ -1,4 +1,11 @@
|
||||
# 测试问题
|
||||
|
||||
## 提现页面,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),每条单份金额,逐条触发退款检测
|
||||
- **已修复**周期佣金位次统计改为按报单商品总件数(而非订单数),确保跨订单轮巡位次连续
|
||||
@@ -34,11 +34,44 @@ class HjfOrderPayJob extends BaseJobs
|
||||
|
||||
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 {
|
||||
/** @var QueuePoolServices $queueServices */
|
||||
$queueServices = app()->make(QueuePoolServices::class);
|
||||
$queueServices->enqueue($uid, $orderId, $amount);
|
||||
Log::info("[HjfOrderPay] 公排入队成功 uid={$uid} orderId={$orderId}");
|
||||
for ($i = 0; $i < $queueQty; $i++) {
|
||||
$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) {
|
||||
Log::warning("[HjfOrderPay] 入队被锁,延迟重试 uid={$uid} orderId={$orderId}: " . $e->getMessage());
|
||||
static::dispatchSece(5, [$uid, $orderId, $amount]);
|
||||
@@ -77,40 +110,15 @@ class HjfOrderPayJob extends BaseJobs
|
||||
}
|
||||
|
||||
// 等级升级完成后发放积分奖励(确保使用升级后的 agent_level)
|
||||
try {
|
||||
$orderRow = Db::name('store_order')
|
||||
->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());
|
||||
}
|
||||
|
||||
if ($orderRow) {
|
||||
try {
|
||||
/** @var PointsRewardServices $pointsService */
|
||||
$pointsService = app()->make(PointsRewardServices::class);
|
||||
$pointsService->reward($uid, $orderId, (int)$orderRow['id'], $preUpgradeLevels, $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;
|
||||
|
||||
@@ -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
|
||||
* @return int
|
||||
@@ -437,14 +461,14 @@ class AgentLevelTaskServices extends BaseServices
|
||||
if (empty($directUids)) {
|
||||
return 0;
|
||||
}
|
||||
// fsgx B5:补充 refund_status 检查,与其他任务类型保持一致,排除已全额退款订单
|
||||
return (int)Db::name('store_order')
|
||||
$orderIds = Db::name('store_order')
|
||||
->whereIn('uid', $directUids)
|
||||
->where('is_queue_goods', 1)
|
||||
->where('paid', 1)
|
||||
->where('is_del', 0)
|
||||
->whereIn('refund_status', [0, 3])
|
||||
->count();
|
||||
->column('id');
|
||||
return $this->sumQueueGoodsQty($orderIds);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -492,14 +516,14 @@ class AgentLevelTaskServices extends BaseServices
|
||||
if ($childGrade >= 2) {
|
||||
continue;
|
||||
}
|
||||
// fsgx B5:补充 refund_status 检查,排除已全额退款订单
|
||||
$total += (int)Db::name('store_order')
|
||||
$childOrderIds = Db::name('store_order')
|
||||
->where('uid', $child['uid'])
|
||||
->where('is_queue_goods', 1)
|
||||
->where('paid', 1)
|
||||
->where('is_del', 0)
|
||||
->whereIn('refund_status', [0, 3])
|
||||
->count();
|
||||
->column('id');
|
||||
$total += $this->sumQueueGoodsQty($childOrderIds);
|
||||
$total += $this->recursiveUmbrellaCount((int)$child['uid'], $remainDepth - 1);
|
||||
}
|
||||
return $total;
|
||||
|
||||
@@ -1028,13 +1028,25 @@ class StoreOrderCreateServices extends BaseServices
|
||||
return '0';
|
||||
}
|
||||
|
||||
// fsgx B6:统计推荐人已完成的报单订单数,作为起始位次基准
|
||||
$completedCount = (int)\think\facade\Db::name('store_order')
|
||||
// fsgx B6:统计推荐人已完成的报单商品总件数(非订单数),作为起始位次基准
|
||||
$completedOrderIds = \think\facade\Db::name('store_order')
|
||||
->where('spread_uid', $spread_uid)
|
||||
->where('is_queue_goods', 1)
|
||||
->where('paid', 1)
|
||||
->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:逐件轮巡,每件商品取下一个位次的佣金比例后累加
|
||||
$total = '0';
|
||||
|
||||
Reference in New Issue
Block a user