feat(commission): 添加分账成功后佣金处理功能

添加了新的方法来处理分账成功后的佣金结算:
- 新增 runCommissionRewardByOrderWithoutWallet 方法用于分账成功时标记已结算
- 新增 runCommissionRewardWithoutWallet 方法处理不入余额的佣金奖励
- 避免在分账成功时重复将佣金计入用户余额

feat(regional_agent): 添加区域代理分账处理逻辑

- 新增 settleByRegionalOrderWithoutWallet 方法处理区域代理分账
- 新增 settleRewardWithoutWallet 方法处理不入钱包的奖励结算
- 完善区域代理佣金处理流程

refactor(split): 优化分账执行器逻辑

- 修改 SplitExecutor 类以支持延迟钱包结算
- 添加异常处理和事务管理
- 支持根据支付网关类型决定是否延迟钱包结算

feat(split): 实现分账完成后钱包结算机制

- 添加 SplitWalletSettlement 类来管理分账与钱包结算的协调
- 支持在分账成功后延迟钱包入账,失败时回退到钱包
- 修复汇付分账与佣金结算的时间冲突问题

refactor(hook): 调整分账钩子事件处理

- 修改 SplitHook 类的事件参数传递
- 更新各个订单状态变更事件的分账触发逻辑
- 确保分账执行时能正确获取事件类型

docs(tests): 更新分账佣金验证说明

- 更新测试文件中的注释说明
- 明确汇付/微信分账成功后的佣金处理方式
```
这个提交包含在:
可乐加冰
2026-09-29 12:37:53 +08:00
父节点 10c35237b3
当前提交 73d65c3f0c
共有 8 个文件被更改,包括 362 次插入 和 90 次删除

查看文件

@@ -22,93 +22,106 @@ class SplitExecutor
public function executeByOrderId($orderId, $event = 'payed')
{
if (!$this->config->isEnable()) {
return false;
}
$order = Order::get($orderId);
$deferWallet = $order && SplitWalletSettlement::shouldDeferForGatewaySplit($order, $event);
$ok = false;
if (class_exists('\\addons\\shopro_huifu\\library\\Bridge')) {
$hookParams = [
'order_id' => $orderId,
'event' => $event,
];
$handled = \think\Hook::listen('shopro_split_execute', $hookParams, null, true);
if ($handled === true) {
try {
if (!$this->config->isEnable()) {
return false;
}
if (class_exists('\\addons\\shopro_huifu\\library\\Bridge')) {
$hookParams = [
'order_id' => $orderId,
'event' => $event,
];
$handled = \think\Hook::listen('shopro_split_execute', $hookParams, null, true);
if ($handled === true) {
$ok = true;
return true;
}
}
$orderCheck = Order::get($orderId);
if ($orderCheck && $orderCheck['pay_type'] === 'huifu_wechat') {
return false;
}
$exists = SplitOrder::where('order_id', $orderId)->where('status', 'in', [1, 2])->find();
if ($exists) {
$ok = true;
return true;
}
}
$orderCheck = Order::get($orderId);
if ($orderCheck && $orderCheck['pay_type'] === 'huifu_wechat') {
return false;
}
$exists = SplitOrder::where('order_id', $orderId)->where('status', 'in', [1, 2])->find();
if ($exists) {
return false;
}
$order = Order::get($orderId);
if (!$order || empty($order['transaction_id'])) {
return false;
}
$items = $this->calculator->calculate($orderId);
if (empty($items)) {
return false;
}
$outOrderNo = 'PS' . date('YmdHis') . $orderId;
$splitAmount = array_sum(array_column($items, 'amount'));
Db::startTrans();
try {
$splitOrder = SplitOrder::create([
'order_id' => $orderId,
'order_sn' => $order['order_sn'],
'transaction_id' => $order['transaction_id'],
'out_order_no' => $outOrderNo,
'total_amount' => $order['pay_fee'],
'split_amount' => $splitAmount,
'status' => 1,
]);
$receivers = [];
foreach ($items as $item) {
SplitOrderReceiver::create([
'split_order_id' => $splitOrder->id,
'receiver_id' => $item['receiver_id'],
'role_type' => $item['role_type'],
'amount' => $item['amount'],
'description' => $item['description'],
'status' => 0,
]);
$receivers[] = [
'type' => $item['receiver_type'],
'account' => $item['receiver_account'],
'name' => $item['receiver_name'] ?? '',
'amount' => intval(round($item['amount'] * 100)),
'description' => $item['description'],
];
$order = Order::get($orderId);
if (!$order || empty($order['transaction_id'])) {
return false;
}
$result = $this->service->createOrder([
'transaction_id' => $order['transaction_id'],
'out_order_no' => $outOrderNo,
'receivers' => $receivers,
'unfreeze_unsplit' => true,
]);
$items = $this->calculator->calculate($orderId);
if (empty($items)) {
return false;
}
$splitOrder->wx_result = is_array($result) ? json_encode($result, JSON_UNESCAPED_UNICODE) : json_encode($result);
$splitOrder->status = 2;
$splitOrder->save();
$outOrderNo = 'PS' . date('YmdHis') . $orderId;
$splitAmount = array_sum(array_column($items, 'amount'));
SplitOrderReceiver::where('split_order_id', $splitOrder->id)->update(['status' => 1]);
Db::commit();
return true;
} catch (\Exception $e) {
Db::rollback();
$this->markFailed($orderId, $outOrderNo ?? ('PS' . $orderId), $order, $items ?? [], $e->getMessage());
return false;
Db::startTrans();
try {
$splitOrder = SplitOrder::create([
'order_id' => $orderId,
'order_sn' => $order['order_sn'],
'transaction_id' => $order['transaction_id'],
'out_order_no' => $outOrderNo,
'total_amount' => $order['pay_fee'],
'split_amount' => $splitAmount,
'status' => 1,
]);
$receivers = [];
foreach ($items as $item) {
SplitOrderReceiver::create([
'split_order_id' => $splitOrder->id,
'receiver_id' => $item['receiver_id'],
'role_type' => $item['role_type'],
'amount' => $item['amount'],
'description' => $item['description'],
'status' => 0,
]);
$receivers[] = [
'type' => $item['receiver_type'],
'account' => $item['receiver_account'],
'name' => $item['receiver_name'] ?? '',
'amount' => intval(round($item['amount'] * 100)),
'description' => $item['description'],
];
}
$result = $this->service->createOrder([
'transaction_id' => $order['transaction_id'],
'out_order_no' => $outOrderNo,
'receivers' => $receivers,
'unfreeze_unsplit' => true,
]);
$splitOrder->wx_result = is_array($result) ? json_encode($result, JSON_UNESCAPED_UNICODE) : json_encode($result);
$splitOrder->status = 2;
$splitOrder->save();
SplitOrderReceiver::where('split_order_id', $splitOrder->id)->update(['status' => 1]);
Db::commit();
$ok = true;
return true;
} catch (\Exception $e) {
Db::rollback();
$this->markFailed($orderId, $outOrderNo ?? ('PS' . $orderId), $order, $items ?? [], $e->getMessage());
return false;
}
} finally {
if ($deferWallet) {
SplitWalletSettlement::finalizeAfterSplitAttempt($orderId, $event, $ok);
}
}
}