wechatPayService = new WeChatPayService($terminal, $userId); $this->balancePayService = new BalancePayService(); } catch (\Exception $e) { $this->setError('混合支付服务初始化失败:' . $e->getMessage()); } } /** * @notes 获取真实支付对象 * @return mixed */ function realPay() { return $this->wechatPayService->realPay(); } /** * @notes 混合支付(余额+微信) * @param $from 订单类型 * @param $order 订单信息 * @return array|false * @author 系统 * @date 2024/12/19 */ public function pay($from, $order) { Db::startTrans(); try { $user = User::findOrEmpty($order['user_id']); if ($user->isEmpty()) { throw new \Exception('用户不存在'); } // 记录调试日志 file_put_contents( runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_pay_debug_' . date('Y-m-d') . '.log', "[" . date('Y-m-d H:i:s') . "] 混合支付开始 - 用户ID: {$order['user_id']}, 订单号: {$order['sn']}, 订单金额: {$order['order_amount']}" . PHP_EOL, FILE_APPEND | LOCK_EX ); $userBalance = $user['user_money']; // 用户余额 $orderAmount = $order['order_amount']; // 订单金额 // 记录余额信息 file_put_contents( runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_pay_debug_' . date('Y-m-d') . '.log', "[" . date('Y-m-d H:i:s') . "] 用户余额: {$userBalance}, 订单金额: {$orderAmount}" . PHP_EOL, FILE_APPEND | LOCK_EX ); // 如果余额足够支付全部订单,直接使用余额支付 if ($userBalance >= $orderAmount) { file_put_contents( runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_pay_debug_' . date('Y-m-d') . '.log', "[" . date('Y-m-d H:i:s') . "] 余额充足,使用纯余额支付" . PHP_EOL, FILE_APPEND | LOCK_EX ); $result = $this->balancePayService->pay($from, $order); if ($result === false) { throw new \Exception('余额支付失败:' . $this->balancePayService->getError()); } Db::commit(); return $result; } // 余额不足,使用混合支付 $balanceAmount = $userBalance; // 使用全部余额 $wechatAmount = $orderAmount - $balanceAmount; // 剩余金额用微信支付 file_put_contents( runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_pay_debug_' . date('Y-m-d') . '.log', "[" . date('Y-m-d H:i:s') . "] 使用混合支付 - 余额部分: {$balanceAmount}, 微信部分: {$wechatAmount}" . PHP_EOL, FILE_APPEND | LOCK_EX ); // 先扣除用户余额 if ($balanceAmount > 0) { //先不扣余额,等为微信支付成功后扣钱 // User::update([ // 'user_money' => ['dec', $balanceAmount] // ], ['id' => $order['user_id']]); // // // 记录余额流水 // AccountLogLogic::add( // $order['user_id'], // AccountLogEnum::BNW_DEC_ORDER, // AccountLogEnum::DEC, // $balanceAmount, // $order['sn'], // '混合支付-余额部分' // ); // // file_put_contents( // runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_pay_debug_' . date('Y-m-d') . '.log', // "[" . date('Y-m-d H:i:s') . "] 余额扣除成功,扣除金额: {$balanceAmount}" . PHP_EOL, // FILE_APPEND | LOCK_EX // ); Order::update([ 'balance_amount' => $balanceAmount ], ['id' => $order['id']]); } // 创建微信支付订单(金额为剩余需要支付的金额) $wechatOrder = $order; $wechatOrder['order_amount'] = round($wechatAmount,2); $wechatOrder['balance_amount'] = $balanceAmount; // 记录已使用的余额金额 file_put_contents( runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_pay_debug_' . date('Y-m-d') . '.log', "[" . date('Y-m-d H:i:s') . "] 开始创建微信支付订单,金额: {$wechatAmount}" . PHP_EOL, FILE_APPEND | LOCK_EX ); outFileLog($wechatOrder,'prepay','$wechatOrder'); // Db::commit(); // return $wechatOrder; $result = $this->wechatPayService->pay($from, $wechatOrder); if ($result === false) { throw new \Exception('微信支付创建失败:' . $this->wechatPayService->getError()); } // 在返回结果中添加混合支付信息 $result['pay_way'] = PayEnum::MIXED_PAY; $result['balance_amount'] = $balanceAmount; $result['wechat_amount'] = $wechatAmount; $result['total_amount'] = $orderAmount; file_put_contents( runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_pay_debug_' . date('Y-m-d') . '.log', "[" . date('Y-m-d H:i:s') . "] 混合支付创建成功" . PHP_EOL, FILE_APPEND | LOCK_EX ); Db::commit(); return $result; } catch (\Exception $e) { Db::rollback(); file_put_contents( runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_pay_debug_' . date('Y-m-d') . '.log', "[" . date('Y-m-d H:i:s') . "] 混合支付失败: " . $e->getMessage() . PHP_EOL, FILE_APPEND | LOCK_EX ); $this->setError($e->getMessage()); return false; } } /** * @notes 混合支付退款 * @param $order 订单信息 * @param $refundAmount 退款金额 * @param $afterSaleId 售后ID * @return bool */ public function refund($order, $refundAmount, $afterSaleId) { Db::startTrans(); try { // 记录退款日志 file_put_contents( runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_refund_debug_' . date('Y-m-d') . '.log', "[" . date('Y-m-d H:i:s') . "] 混合支付退款开始 - 订单号: {$order['sn']}, 退款金额: {$refundAmount}" . PHP_EOL, FILE_APPEND | LOCK_EX ); // 获取订单的余额支付金额和微信支付金额 $balanceAmount = $order['balance_amount'] ?? 0; $wechatAmount = $order['order_amount'] - $balanceAmount; // 计算退款比例 $refundRatio = $refundAmount / $order['order_amount']; $refundBalanceAmount = round($balanceAmount * $refundRatio, 2); $refundWechatAmount = round($wechatAmount * $refundRatio, 2); // 确保退款金额精确 $totalCalculated = $refundBalanceAmount + $refundWechatAmount; if ($totalCalculated != $refundAmount) { $diff = $refundAmount - $totalCalculated; if ($refundWechatAmount > 0) { $refundWechatAmount += $diff; } else { $refundBalanceAmount += $diff; } } file_put_contents( runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_refund_debug_' . date('Y-m-d') . '.log', "[" . date('Y-m-d H:i:s') . "] 退款分配 - 余额退款: {$refundBalanceAmount}, 微信退款: {$refundWechatAmount}" . PHP_EOL, FILE_APPEND | LOCK_EX ); // 处理余额退款 if ($refundBalanceAmount > 0) { // 返回余额 User::update([ 'user_money' => ['inc', $refundBalanceAmount] ], ['id' => $order['user_id']]); // 记录余额流水 $afterSale = AfterSale::findOrEmpty($afterSaleId); AccountLogLogic::add( $order['user_id'], AccountLogEnum::BNW_INC_AFTER_SALE, AccountLogEnum::INC, $refundBalanceAmount, $afterSale->sn, '混合支付退款-余额部分' ); file_put_contents( runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_refund_debug_' . date('Y-m-d') . '.log', "[" . date('Y-m-d H:i:s') . "] 余额退款完成: {$refundBalanceAmount}" . PHP_EOL, FILE_APPEND | LOCK_EX ); } // 处理微信退款 if ($refundWechatAmount > 0) { // 记录退款日志 file_put_contents( runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_refund_debug_' . date('Y-m-d') . '.log', "[" . date('Y-m-d H:i:s') . "] 混合支付退款开始 - 订单号: {$order['sn']}, 微信退款金额: {$refundWechatAmount}" . PHP_EOL, FILE_APPEND | LOCK_EX ); file_put_contents( runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_refund_debug_' . date('Y-m-d') . '.log', "[" . date('Y-m-d H:i:s') . "] 混合支付退款开始 - 订单号: {$order['sn']}, 微信支付金额: {$wechatAmount}" . PHP_EOL, FILE_APPEND | LOCK_EX ); $pay = new WeChatPayService($order['order_terminal']); $result = $pay->refund([ 'transaction_id' => $order['transaction_id'], 'refund_sn' => 'mixed_refund_' . $order['sn'] . '_' . time(), 'total_fee' => round($wechatAmount,2), 'refund_fee' => $refundWechatAmount, ]); if ($result !== true) { throw new \Exception($pay->realPay()->getMessage()); } // //更新退款日志记录 // Refund::update([ // 'wechat_refund_id' => 0, // 'refund_status' => 1, // 'refund_msg' => json_encode([], JSON_UNESCAPED_UNICODE), // ], ['id' => self::$refund['id']]); // $refundData = [ // 'transaction_id' => $order['transaction_id'], // 'refund_sn' => 'mixed_refund_' . $order['sn'] . '_' . time(), // 'total_fee' => $wechatAmount, // 'refund_fee' => $refundWechatAmount, // ]; // // $result = $this->wechatPayService->refund($refundData); // if ($result !== true) { // throw new \Exception('微信退款失败:' . $this->wechatPayService->getError()); // } file_put_contents( runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_refund_debug_' . date('Y-m-d') . '.log', "[" . date('Y-m-d H:i:s') . "] 微信退款完成: {$refundWechatAmount}" . PHP_EOL, FILE_APPEND | LOCK_EX ); } // 更新售后状态 $afterSale = AfterSale::findOrEmpty($afterSaleId); if (!$afterSale->isEmpty()) { // 判断退款状态 $refundStatus = ($refundAmount >= $order['order_amount']) ? AfterSaleEnum::FULL_REFUND : AfterSaleEnum::PARTIAL_REFUND; $afterSale->status = AfterSaleEnum::STATUS_SUCCESS; $afterSale->sub_status = AfterSaleEnum::SUB_STATUS_SELLER_REFUND_SUCCESS; $afterSale->refund_status = $refundStatus; $afterSale->save(); // 添加售后日志 AfterSaleService::createAfterLog( $afterSale->id, '系统已完成混合支付退款', 0, AfterSaleLogEnum::ROLE_SYS ); // 发送退款成功通知 event('Notice', [ 'scene_id' => NoticeEnum::REFUND_SUCCESS_NOTICE, 'params' => [ 'user_id' => $afterSale->user_id, 'order_sn' => $order['sn'], 'after_sale_sn' => $afterSale->sn, 'refund_type' => AfterSaleEnum::getRefundTypeDesc($afterSale->refund_type), 'refund_total_amount' => $afterSale->refund_total_amount, 'refund_time' => date('Y-m-d H:i:s'), ] ]); } file_put_contents( runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_refund_debug_' . date('Y-m-d') . '.log', "[" . date('Y-m-d H:i:s') . "] 混合支付退款成功" . PHP_EOL, FILE_APPEND | LOCK_EX ); Db::commit(); return true; } catch (\Exception $e) { Db::rollback(); file_put_contents( runtime_path() . 'log' . DIRECTORY_SEPARATOR . 'mixed_refund_debug_' . date('Y-m-d') . '.log', "[" . date('Y-m-d H:i:s') . "] 混合支付退款失败: " . $e->getMessage() . PHP_EOL, FILE_APPEND | LOCK_EX ); $this->setError($e->getMessage()); return false; } } }