diff --git a/addons/shopro/library/commission/Commission.php b/addons/shopro/library/commission/Commission.php index 7d5a4ea..fca6125 100644 --- a/addons/shopro/library/commission/Commission.php +++ b/addons/shopro/library/commission/Commission.php @@ -14,6 +14,8 @@ use addons\shopro\model\commission\Order as OrderModel; use addons\shopro\model\commission\Reward as RewardModel; +use addons\shopro\library\commission\Reward as RewardLibrary; + /** @@ -193,7 +195,7 @@ class Commission if ($commissionOrder) { - return $commissionOrder; + return $this->syncExistingCommissionOrderOnPay($commissionOrder); } @@ -225,17 +227,7 @@ class Commission 'commission_price_type' => $this->_config->getCommissionPriceType(), - 'commission_rules' => json_encode([ - - 'rules' => $this->goods->getCommissionRules(), - - 'differential_enable' => $this->goods->isDifferentialEnable() ? 1 : 0, - - 'management_enable' => $this->goods->isManagementEnable() ? 1 : 0, - - 'repurchase_enable' => $this->goods->isRepurchaseEnable() ? 1 : 0, - - ]), + 'commission_rules' => $this->encodeCommissionRulesSnapshot(), 'commission_event' => $this->_config->getCommissionEvent(), @@ -279,6 +271,128 @@ class Commission + /** + * 支付时若已存在分销单(测试/脏数据/提前写入),与当前订单项不一致则同步并重算待发佣金 + */ + protected function syncExistingCommissionOrderOnPay($commissionOrder) + { + $agentId = $this->selfBuy + ? $this->buyer->user->id + : ($this->buyer->getParentAgentId() ?: $this->buyer->user->id); + + $newAmount = round(floatval($this->amount), 2); + $oldAmount = round(floatval($commissionOrder->amount), 2); + $newPriceType = $this->_config->getCommissionPriceType(); + $newRulesJson = $this->encodeCommissionRulesSnapshot(); + + $needsSync = ( + abs($newAmount - $oldAmount) >= 0.01 + || intval($commissionOrder->order_id) !== intval($this->item['order_id']) + || intval($commissionOrder->agent_id) !== intval($agentId) + || (string) $commissionOrder->commission_price_type !== (string) $newPriceType + || !$this->commissionRulesSnapshotEquals($commissionOrder->commission_rules, $newRulesJson) + ); + + if (!$needsSync) { + return $commissionOrder; + } + + $accountedCount = RewardModel::where('commission_order_id', $commissionOrder->id) + ->where('status', RewardLibrary::COMMISSION_REWARD_STATUS_ACCOUNTED) + ->count(); + if ($accountedCount > 0) { + \think\Log::warning(sprintf( + '[commission] skip sync commission_order id=%d order_item_id=%d: %d accounted reward(s), old_amount=%s new_amount=%s', + $commissionOrder->id, + $this->item['id'], + $accountedCount, + $oldAmount, + $newAmount + )); + return $commissionOrder; + } + + RewardModel::where('commission_order_id', $commissionOrder->id) + ->where('status', RewardLibrary::COMMISSION_REWARD_STATUS_WAITING) + ->delete(); + + if ( + intval($commissionOrder->commission_order_status) === OrderModel::COMMISSION_ORDER_STATUS_YES + && abs($newAmount - $oldAmount) >= 0.01 + ) { + $orderAgent = new Agent($commissionOrder->agent_id); + if ($orderAgent->isAgentAvaliable()) { + $delta = bcsub((string) $newAmount, (string) $oldAmount, 2); + if (bccomp($delta, '0', 2) > 0) { + $orderAgent->agent->setInc('order_money', $delta); + } elseif (bccomp($delta, '0', 2) < 0) { + $dec = ltrim($delta, '-'); + if (bccomp((string) $orderAgent->agent->order_money, $dec, 2) < 0) { + $orderAgent->agent->order_money = 0; + } else { + $orderAgent->agent->setDec('order_money', $dec); + } + } + $orderAgent->agent->save(); + } + } + + $commissionOrder->self_buy = intval($this->selfBuy); + $commissionOrder->order_id = intval($this->item['order_id']); + $commissionOrder->buyer_id = $this->buyer->user->id; + $commissionOrder->goods_id = $this->item['goods_id']; + $commissionOrder->agent_id = intval($agentId); + $commissionOrder->amount = $newAmount; + $commissionOrder->commission_price_type = $newPriceType; + $commissionOrder->commission_rules = $newRulesJson; + $commissionOrder->commission_event = $this->_config->getCommissionEvent(); + if (intval($commissionOrder->commission_reward_status) !== RewardLibrary::COMMISSION_REWARD_STATUS_WAITING) { + $commissionOrder->commission_reward_status = RewardLibrary::COMMISSION_REWARD_STATUS_WAITING; + $commissionOrder->commission_time = null; + } + $commissionOrder->save(); + + \think\Log::info(sprintf( + '[commission] synced commission_order id=%d order_item_id=%d amount %s -> %s', + $commissionOrder->id, + $this->item['id'], + $oldAmount, + $newAmount + )); + + return $commissionOrder; + } + + + + protected function encodeCommissionRulesSnapshot() + { + return json_encode([ + 'rules' => $this->goods->getCommissionRules(), + 'differential_enable' => $this->goods->isDifferentialEnable() ? 1 : 0, + 'management_enable' => $this->goods->isManagementEnable() ? 1 : 0, + 'repurchase_enable' => $this->goods->isRepurchaseEnable() ? 1 : 0, + ], JSON_UNESCAPED_UNICODE); + } + + + + protected function commissionRulesSnapshotEquals($stored, $newJson) + { + $left = json_decode($stored ?: '{}', true); + $right = json_decode($newJson ?: '{}', true); + if (!is_array($left)) { + $left = []; + } + if (!is_array($right)) { + $right = []; + } + + return json_encode($left, JSON_UNESCAPED_UNICODE) === json_encode($right, JSON_UNESCAPED_UNICODE); + } + + + /** * 执行分销计划:关系链、级差、管理奖可同时发放 diff --git a/addons/shopro/library/regional_agent/Commission.php b/addons/shopro/library/regional_agent/Commission.php index c81957f..1940e2d 100644 --- a/addons/shopro/library/regional_agent/Commission.php +++ b/addons/shopro/library/regional_agent/Commission.php @@ -292,7 +292,7 @@ class Commission $agent->setInc('order_count', 1); if ($this->_config->getCommissionEvent() === 'payed') { - if (!SplitWalletSettlement::shouldDeferRegionalWallet($order, 'payed')) { + if (SplitWalletSettlement::shouldSettleRegionalViaWalletHook($order, 'payed')) { (new Reward())->settleByRegionalOrder($regionalOrder->id, 'payed'); } } @@ -311,7 +311,11 @@ class Commission $rewardLib = new Reward(); foreach ($regionalOrders as $regionalOrder) { - if ($regionalOrder['commission_event'] === $event) { + if ($regionalOrder['commission_event'] !== $event) { + continue; + } + $order = \addons\shopro\model\Order::get($regionalOrder->order_id); + if ($order && SplitWalletSettlement::shouldSettleRegionalViaWalletHook($order, $event)) { $rewardLib->settleByRegionalOrder($regionalOrder->id, $event); } } diff --git a/addons/shopro/library/split/SplitWalletSettlement.php b/addons/shopro/library/split/SplitWalletSettlement.php index fd98b0b..ab24bd8 100644 --- a/addons/shopro/library/split/SplitWalletSettlement.php +++ b/addons/shopro/library/split/SplitWalletSettlement.php @@ -38,6 +38,38 @@ class SplitWalletSettlement return self::shouldDeferWalletUntilGatewaySplitResolves($order); } + /** + * 分销钩子是否应把待发佣金写入余额(false = 等分账 finalize 或已走通道,避免与汇付/微信分账重复) + */ + public static function shouldSettleCommissionViaWalletHook($order, $event) + { + $commissionEvent = (new CommissionConfig())->getCommissionEvent(); + if ($commissionEvent !== $event && $event !== 'admin') { + return false; + } + if (self::shouldDeferWalletUntilGatewaySplitResolves($order)) { + return false; + } + + return true; + } + + /** + * 区域代理钩子是否应把待发佣金写入余额 + */ + public static function shouldSettleRegionalViaWalletHook($order, $event) + { + $regionalEvent = (new RegionalConfig())->getCommissionEvent(); + if ($regionalEvent !== $event && $event !== 'admin') { + return false; + } + if (self::shouldDeferWalletUntilGatewaySplitResolves($order)) { + return false; + } + + return true; + } + /** * 分销/区域结算事件(如 payed)早于 split_timing(如 confirm)时,仍应等分账结束再入钱包 */ @@ -54,8 +86,9 @@ class SplitWalletSettlement if (!$config->isEnable() || !$config->shouldSkipWallet()) { return false; } + // 分账已成功:佣金应由 finalizeAfterSplitAttempt 处理(或已标记通道到账),钩子不得再入余额 if (self::isSplitSuccessful($order['id'])) { - return false; + return true; } if (class_exists('\\addons\\shopro_huifu\\library\\Bridge') diff --git a/addons/shopro/listener/commission/CommissionHook.php b/addons/shopro/listener/commission/CommissionHook.php index 4e652e0..75cbbb4 100644 --- a/addons/shopro/listener/commission/CommissionHook.php +++ b/addons/shopro/listener/commission/CommissionHook.php @@ -50,7 +50,7 @@ class CommissionHook // 执行奖金计划 $commission->runCommissionPlan($commissionOrder); // 支付后拨款(汇付分账同事件时延至分账结果后再结算) - if (!SplitWalletSettlement::shouldDeferCommissionWallet($order, 'payed')) { + if (SplitWalletSettlement::shouldSettleCommissionViaWalletHook($order, 'payed')) { (new RewardLibrary())->runCommissionRewardByOrder('payed', $commissionOrder->id); } } @@ -102,7 +102,10 @@ class CommissionHook $commissionOrder = \addons\shopro\model\commission\Order::get(['order_item_id' => $item['id']]); if ($commissionOrder) { - (new RewardLibrary())->runCommissionRewardByOrder('confirm', $commissionOrder); + $order = Order::get($commissionOrder->order_id); + if ($order && SplitWalletSettlement::shouldSettleCommissionViaWalletHook($order, 'confirm')) { + (new RewardLibrary())->runCommissionRewardByOrder('confirm', $commissionOrder); + } } } @@ -110,9 +113,13 @@ class CommissionHook public function orderFinish(&$params) { $order = $params['order']; - foreach ($order['item'] as $item) { + $orderRow = Order::with('item')->where('id', $order['id'])->find(); + if (!$orderRow) { + return; + } + foreach ($orderRow['item'] as $item) { $commissionOrder = \addons\shopro\model\commission\Order::get(['order_item_id' => $item['id']]); - if ($commissionOrder) { + if ($commissionOrder && SplitWalletSettlement::shouldSettleCommissionViaWalletHook($orderRow, 'finish')) { (new RewardLibrary())->runCommissionRewardByOrder('finish', $commissionOrder); } } diff --git a/addons/shopro/tests/split_commission_verify.sql b/addons/shopro/tests/split_commission_verify.sql index 4466446..40a2da4 100644 --- a/addons/shopro/tests/split_commission_verify.sql +++ b/addons/shopro/tests/split_commission_verify.sql @@ -127,7 +127,7 @@ GROUP BY pay_type; -- 网关分账:fa_shopro_split_order_receiver + receiver 表(汇付 huifu_id / 微信 openid) -- 业务佣金:fa_shopro_commission_reward / fa_shopro_regional_agent_reward -- 钱包入账:fa_shopro_user_wallet_log type=commission_income / regional_agent_income --- 代码说明:shouldSkipWallet() 尚未接入 Reward,分账开启时仍可能同时入账钱包(需重点核对) +-- 代码说明:SplitWalletSettlement + shouldSettle*ViaWalletHook 控制分账成功不入余额;§9 仍用于核对历史数据 SELECT '=== 7. 分账成功订单明细(最近 30 笔)===' AS section; @@ -298,11 +298,12 @@ LIMIT 20; SELECT '=== 12. 有推广/区域佣金但缺少汇付接收方(导致无法分账)===' AS section; +-- 推广:r.agent_id 即分销商 user_id(非 commission_agent 表主键) SELECT DISTINCT r.order_id, o.order_sn, 'commission' AS reward_source, - a.user_id AS beneficiary_user_id, + r.agent_id AS beneficiary_user_id, u.mobile, ho.huifu_id AS onboard_huifu_id, sr.id AS split_receiver_id @@ -318,6 +319,26 @@ WHERE r.status >= 0 AND sr.id IS NULL LIMIT 30; +SELECT DISTINCT + rr.order_id, + o.order_sn, + 'regional_agent' AS reward_source, + rr.agent_user_id AS beneficiary_user_id, + u.mobile, + ho.huifu_id AS onboard_huifu_id, + sr.id AS split_receiver_id +FROM fa_shopro_regional_agent_reward rr +INNER JOIN fa_shopro_order o ON o.id = rr.order_id +INNER JOIN fa_user u ON u.id = rr.agent_user_id +LEFT JOIN fa_shopro_huifu_onboard ho ON ho.user_id = rr.agent_user_id AND ho.onboard_status = 'approved' +LEFT JOIN fa_shopro_split_receiver sr ON sr.role_type = 'regional_agent' + AND sr.role_id = rr.agent_user_id AND sr.channel = 'huifu' AND sr.status = 'normal' +WHERE rr.status >= 0 + AND o.pay_type = 'huifu_wechat' + AND o.paytime >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 90 DAY)) + AND sr.id IS NULL +LIMIT 30; + SELECT '=== 13. 延时分账标记:支付扩展 delay_acct(近90天汇付单抽样)===' AS section; SELECT @@ -343,37 +364,160 @@ FROM fa_shopro_split_receiver GROUP BY channel, role_type; -- ============================================================================= --- 五、单笔订单深度核验(把 @order_sn 改成实际订单号后执行) +-- 五、单笔订单深度核验 +-- 用法:只改下面一行 @order_id 或 @order_sn,然后整段执行 +-- 预设:77 = 598单 202605495163454091004900;74 = 分账成功样例 202609215157744091003800 -- ============================================================================= -/* -SET @order_sn = '2025010100000001'; -SELECT o.* FROM fa_shopro_order o WHERE o.order_sn = @order_sn; +SET @order_id = 77; +-- SET @order_sn = '202605495163454091004900'; +-- SET @order_id = (SELECT id FROM fa_shopro_order WHERE order_sn = @order_sn LIMIT 1); -SELECT * FROM fa_shopro_split_order WHERE order_sn = @order_sn; -SELECT sor.*, sr.receiver_account, sr.channel -FROM fa_shopro_split_order_receiver sor +SELECT '=== 5.1 订单主表 ===' AS section; +-- 确认/完成时间在 ext JSON(confirm_time / finish_time),非独立字段 +SELECT id, order_sn, status, pay_type, pay_fee, total_fee, + FROM_UNIXTIME(paytime) AS pay_time, + FROM_UNIXTIME( + NULLIF(CAST(JSON_UNQUOTE(JSON_EXTRACT(ext, '$.confirm_time')) AS UNSIGNED), 0) + ) AS confirm_time, + FROM_UNIXTIME( + NULLIF(CAST(JSON_UNQUOTE(JSON_EXTRACT(ext, '$.finish_time')) AS UNSIGNED), 0) + ) AS finish_time, + FROM_UNIXTIME(updatetime) AS order_updated, + ext +FROM fa_shopro_order WHERE id = @order_id; + +SELECT '=== 5.2 订单商品行 ===' AS section; +SELECT id AS order_item_id, goods_id, goods_title, goods_price, goods_num, + pay_price, discount_fee, ext +FROM fa_shopro_order_item WHERE order_id = @order_id; + +SELECT '=== 5.3 汇付支付扩展 delay_acct ===' AS section; +SELECT order_id, delay_acct_flag, confirm_status, confirm_hf_seq_id, hf_seq_id, trans_stat, + LEFT(extra, 200) AS extra_preview +FROM fa_shopro_huifu_pay_ext WHERE order_id = @order_id; + +SELECT '=== 5.4 分账单(全部状态)===' AS section; +SELECT id, channel, status, + CASE status WHEN 0 THEN '待分账' WHEN 1 THEN '分账中' WHEN 2 THEN '成功' + WHEN 3 THEN '部分成功' WHEN 4 THEN '失败' ELSE status END AS status_label, + total_amount, split_amount, confirm_hf_seq_id, + FROM_UNIXTIME(createtime) AS created_at, + LEFT(wx_result, 180) AS result_msg +FROM fa_shopro_split_order WHERE order_id = @order_id +ORDER BY id DESC; + +SELECT '=== 5.5 分账接收方明细 ===' AS section; +SELECT so.order_sn, sor.role_type, sor.amount, sor.description, sor.status AS line_status, + sr.receiver_account, sr.receiver_type, sr.channel, sr.receiver_name, sr.role_id AS user_id +FROM fa_shopro_split_order so +INNER JOIN fa_shopro_split_order_receiver sor ON sor.split_order_id = so.id LEFT JOIN fa_shopro_split_receiver sr ON sr.id = sor.receiver_id -WHERE sor.split_order_id IN (SELECT id FROM fa_shopro_split_order WHERE order_sn = @order_sn); +WHERE so.order_id = @order_id +ORDER BY so.id DESC, sor.id; -SELECT * FROM fa_shopro_commission_reward WHERE order_id = (SELECT id FROM fa_shopro_order WHERE order_sn = @order_sn LIMIT 1); -SELECT rr.* +SELECT '=== 5.6 分销单 + 推广佣金 ===' AS section; +SELECT co.id AS commission_order_id, co.order_item_id, co.amount AS dist_base, + co.commission_price_type, co.commission_event, + co.commission_reward_status, FROM_UNIXTIME(co.createtime) AS co_created, + FROM_UNIXTIME(co.commission_time) AS co_settled, + LEFT(co.commission_rules, 120) AS rules_preview +FROM fa_shopro_commission_order co +WHERE co.order_id = @order_id; + +SELECT r.id AS reward_id, r.agent_id AS user_id, u.nickname, u.mobile, + r.commission_level, r.commission, r.status, + CASE r.status WHEN 0 THEN '待入账' WHEN 1 THEN '已入账' WHEN -1 THEN '已退回' ELSE r.status END AS status_label, + r.commission_rules, FROM_UNIXTIME(r.createtime) AS reward_created +FROM fa_shopro_commission_reward r +LEFT JOIN fa_user u ON u.id = r.agent_id +WHERE r.order_id = @order_id +ORDER BY r.id; + +SELECT '=== 5.7 区域代理单 + 区域佣金 ===' AS section; +SELECT ro.id AS regional_order_id, ro.amount AS regional_base, ro.commission_event, + ro.commission_reward_status, FROM_UNIXTIME(ro.createtime) AS ro_created +FROM fa_shopro_regional_agent_order ro +WHERE ro.order_id = @order_id; + +SELECT rr.id AS reward_id, rr.agent_user_id AS user_id, u.nickname, u.mobile, + rr.commission, rr.status, + CASE rr.status WHEN 0 THEN '待入账' WHEN 1 THEN '已入账' WHEN -1 THEN '已退回' ELSE rr.status END AS status_label, + FROM_UNIXTIME(rr.createtime) AS reward_created FROM fa_shopro_regional_agent_reward rr -INNER JOIN fa_shopro_regional_agent_order ro ON ro.id = rr.regional_order_id -WHERE ro.order_id = (SELECT id FROM fa_shopro_order WHERE order_sn = @order_sn LIMIT 1); +LEFT JOIN fa_user u ON u.id = rr.agent_user_id +WHERE rr.order_id = @order_id +ORDER BY rr.id; -SELECT wl.* +SELECT '=== 5.8 钱包流水(佣金/区域)===' AS section; +SELECT wl.id, wl.user_id, wl.type, wl.wallet, wl.item_id, + FROM_UNIXTIME(wl.createtime) AS log_time, LEFT(wl.memo, 80) AS memo FROM fa_shopro_user_wallet_log wl WHERE wl.wallet_type = 'money' AND wl.type IN ('commission_income', 'regional_agent_income', 'commission_back', 'regional_agent_back') AND ( - wl.item_id IN (SELECT id FROM fa_shopro_commission_reward WHERE order_id = (SELECT id FROM fa_shopro_order WHERE order_sn = @order_sn LIMIT 1)) - OR wl.item_id IN ( - SELECT rr.id FROM fa_shopro_regional_agent_reward rr - INNER JOIN fa_shopro_regional_agent_order ro ON ro.id = rr.regional_order_id - WHERE ro.order_id = (SELECT id FROM fa_shopro_order WHERE order_sn = @order_sn LIMIT 1) - ) - ); + wl.item_id IN (SELECT id FROM fa_shopro_commission_reward WHERE order_id = @order_id) + OR wl.item_id IN (SELECT id FROM fa_shopro_regional_agent_reward WHERE order_id = @order_id) + ) +ORDER BY wl.id; -SELECT * FROM fa_shopro_huifu_pay_ext WHERE order_id = (SELECT id FROM fa_shopro_order WHERE order_sn = @order_sn LIMIT 1); -*/ +SELECT '=== 5.9 已入账佣金但无钱包流水(应为通道分账/仅记 total_income)===' AS section; +SELECT 'commission' AS src, r.id AS reward_id, r.agent_id AS user_id, r.commission, + IF(wl.id IS NULL, '无 wallet_log(符合 gateway)', '有 wallet_log(可能双发)') AS wallet_check +FROM fa_shopro_commission_reward r +LEFT JOIN fa_shopro_user_wallet_log wl ON wl.wallet_type = 'money' + AND wl.type = 'commission_income' AND wl.item_id = r.id +WHERE r.order_id = @order_id AND r.status = 1 +UNION ALL +SELECT 'regional', rr.id, rr.agent_user_id, rr.commission, + IF(wl.id IS NULL, '无 wallet_log(符合 gateway)', '有 wallet_log(可能双发)') +FROM fa_shopro_regional_agent_reward rr +LEFT JOIN fa_shopro_user_wallet_log wl ON wl.wallet_type = 'money' + AND wl.type = 'regional_agent_income' AND wl.item_id = rr.id +WHERE rr.order_id = @order_id AND rr.status = 1; + +SELECT '=== 5.10 本单结论(与 §9 同逻辑)===' AS section; +SELECT + o.order_sn, + o.pay_fee, + IFNULL(so.split_amount, 0) AS gateway_split_sum, + IFNULL(cr.dist_sum, 0) AS dist_reward_sum, + IFNULL(rr.reg_sum, 0) AS regional_reward_sum, + IFNULL(wl.w_comm, 0) AS wallet_commission, + IFNULL(wl.w_reg, 0) AS wallet_regional, + CASE + WHEN IFNULL(wl.w_comm, 0) + IFNULL(wl.w_reg, 0) > 0 AND IFNULL(so.split_amount, 0) > 0 + THEN '⚠ 网关已分账且钱包也有流水' + WHEN IFNULL(so.split_amount, 0) > 0 + AND IFNULL(wl.w_comm, 0) + IFNULL(wl.w_reg, 0) = 0 + THEN '✓ 分账成功且未进钱包(或仅记收益)' + WHEN IFNULL(so.id, 0) = 0 OR so.status NOT IN (2, 3) + THEN '未分账成功:佣金可能在钱包或仍待结算' + ELSE '请人工核对' + END AS check_hint +FROM fa_shopro_order o +LEFT JOIN ( + SELECT order_id, MAX(id) AS id, MAX(split_amount) AS split_amount, MAX(status) AS status + FROM fa_shopro_split_order WHERE channel = 'huifu' GROUP BY order_id +) so ON so.order_id = o.id +LEFT JOIN ( + SELECT order_id, SUM(commission) AS dist_sum FROM fa_shopro_commission_reward WHERE status >= 0 GROUP BY order_id +) cr ON cr.order_id = o.id +LEFT JOIN ( + SELECT order_id, SUM(commission) AS reg_sum FROM fa_shopro_regional_agent_reward WHERE status >= 0 GROUP BY order_id +) rr ON rr.order_id = o.id +LEFT JOIN ( + SELECT order_id, + SUM(CASE WHEN wl.type = 'commission_income' THEN wl.wallet ELSE 0 END) AS w_comm, + SUM(CASE WHEN wl.type = 'regional_agent_income' THEN wl.wallet ELSE 0 END) AS w_reg + FROM ( + SELECT cr.order_id, wl.type, wl.wallet + FROM fa_shopro_commission_reward cr + INNER JOIN fa_shopro_user_wallet_log wl ON wl.item_id = cr.id AND wl.type = 'commission_income' AND wl.wallet_type = 'money' + UNION ALL + SELECT rr.order_id, wl.type, wl.wallet + FROM fa_shopro_regional_agent_reward rr + INNER JOIN fa_shopro_user_wallet_log wl ON wl.item_id = rr.id AND wl.type = 'regional_agent_income' AND wl.wallet_type = 'money' + ) wl GROUP BY order_id +) wl ON wl.order_id = o.id +WHERE o.id = @order_id;