feat(commission): 完善分销订单支付时数据同步机制

- 新增 syncExistingCommissionOrderOnPay 方法处理已存在分销单的支付同步场景
- 添加 encodeCommissionRulesSnapshot 和 commissionRulesSnapshotEquals 辅助方法
- 优化佣金规则快照存储方式,统一JSON编码格式
- 增加已入账奖励数量检查,防止对已结算订单进行错误同步

fix(wallet-settlement): 调整分账和佣金结算的余额处理逻辑

- 新增 shouldSettleCommissionViaWalletHook 和 shouldSettleRegionalViaWalletHook
  方法控制分账成功后的钱包入账行为
- 修改 shouldDeferRegionalWallet 调用为 shouldSettleRegionalViaWalletHook
- 修复分账成功时仍可能重复入钱包的问题
- 统一佣金和区域代理的钩子结算判断逻辑

refactor(hook): 优化佣金钩子触发条件和订单查询逻辑

- 在 CommissionHook 中使用新的钱包结算判断方法
- 修正 orderFinish 事件中的订单项遍历逻辑
- 增加订单有效性检查,避免空值异常
- 统一各事件中的结算条件判断

test(sql): 更新分账佣金验证SQL脚本

- 修正注释说明,明确分账成功不入余额的控制逻辑
- 补充区域代理佣金缺失汇付接收方的查询
- 重构单笔订单深度核验脚本,提供更详细的订单分析信息
- 增加分账成功与钱包流水的对比检查逻辑
```
这个提交包含在:
可乐加冰
2026-10-22 11:44:24 +08:00
父节点 b457b9b434
当前提交 b5142ff780
共有 5 个文件被更改,包括 345 次插入 和 43 次删除

查看文件

@@ -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);
}
/**
* 执行分销计划:关系链、级差、管理奖可同时发放

查看文件

@@ -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);
}
}

查看文件

@@ -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')

查看文件

@@ -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);
}
}

查看文件

@@ -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;