config = new Config(); $this->service = new ProfitSharingService(); $this->calculator = new SplitCalculator(); } public function executeByOrderId($orderId, $event = 'payed') { $order = Order::get($orderId); $deferWallet = $order && SplitWalletSettlement::shouldDeferForGatewaySplit($order, $event); $ok = false; 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; } $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'], ]; } $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); } } } public function retry($splitOrderId) { $splitOrder = SplitOrder::get($splitOrderId, ['receivers']); if (!$splitOrder) { return false; } if (($splitOrder['channel'] ?? 'wechat') === 'huifu' && class_exists('\\addons\\shopro_huifu\\library\\HuifuSplitService')) { return (new \addons\shopro_huifu\library\HuifuSplitService())->retry($splitOrderId); } try { $receivers = []; foreach ($splitOrder['receivers'] as $row) { $receiver = \addons\shopro\model\split\Receiver::get($row['receiver_id']); if (!$receiver) { continue; } $receivers[] = [ 'type' => $receiver['receiver_type'], 'account' => $receiver['receiver_account'], 'name' => $receiver['receiver_name'] ?? '', 'amount' => intval(round($row['amount'] * 100)), 'description' => $row['description'], ]; } $result = $this->service->createOrder([ 'transaction_id' => $splitOrder['transaction_id'], 'out_order_no' => $splitOrder['out_order_no'] . 'R' . ($splitOrder['retry_count'] + 1), 'receivers' => $receivers, 'unfreeze_unsplit' => true, ]); $splitOrder->status = 2; $splitOrder->wx_result = json_encode($result, JSON_UNESCAPED_UNICODE); $splitOrder->retry_count = $splitOrder['retry_count'] + 1; $splitOrder->next_retry_time = null; $splitOrder->save(); return true; } catch (\Exception $e) { $splitOrder->retry_count = $splitOrder['retry_count'] + 1; $splitOrder->status = 4; $splitOrder->next_retry_time = time() + $this->config->getRetryInterval(); $splitOrder->wx_result = $e->getMessage(); $splitOrder->save(); return false; } } public function returnByOrderId($orderId) { $splitOrder = SplitOrder::where('order_id', $orderId)->where('status', 2)->find(); if (!$splitOrder) { return false; } try { foreach ($splitOrder->receivers as $row) { $this->service->returnOrder([ 'out_order_no' => $splitOrder['out_order_no'], 'out_return_no' => 'RT' . $splitOrder['id'] . $row['id'], 'return_mchid' => '', 'amount' => intval(round($row['amount'] * 100)), 'description' => '订单退款分账回退', ]); } $splitOrder->status = 4; $splitOrder->save(); return true; } catch (\Exception $e) { \think\Log::error('split-return-error:' . $e->getMessage()); return false; } } protected function markFailed($orderId, $outOrderNo, $order, $items, $message) { $splitOrder = SplitOrder::where('order_id', $orderId)->find(); if (!$splitOrder) { $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' => array_sum(array_column($items, 'amount')), 'status' => 4, 'wx_result' => $message, 'retry_count' => 1, 'next_retry_time' => time() + $this->config->getRetryInterval(), ]); } else { $splitOrder->status = 4; $splitOrder->wx_result = $message; $splitOrder->retry_count = $splitOrder['retry_count'] + 1; $splitOrder->next_retry_time = time() + $this->config->getRetryInterval(); $splitOrder->save(); } SplitOrderHelper::syncReceivers($splitOrder->id, $items); } }