123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- <?php
- namespace App\Services\Client;
- use App\Models\Order;
- use App\Enums\OrderStatus;
- use App\Enums\UserStatus;
- use App\Models\MemberUser;
- use EasyWeChat\Pay\Message;
- use Illuminate\Http\Request;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- use Illuminate\Support\Facades\Auth;
- use EasyWeChat\Pay\Application;
- class PaymentService
- {
- private Application $app;
- public function __construct()
- {
- $this->app = new Application(config('wechat.pay.default'));
- }
- /**
- * [微信]获取支付配置
- *
- * @param int $orderId 订单编号
- * @return array
- * @throws Exception
- */
- public function getPaymentConfig($orderId)
- {
- // 获取当前用户
- $userId = Auth::id();
- $user = MemberUser::where('state', UserStatus::OPEN->value)->findOrFail($userId);
- // 查询订单
- $order = Order::where('id', $orderId)
- ->where('user_id', $userId)
- ->where('state', OrderStatus::CREATED->value)
- ->firstOrFail();
- // 生成微信支付配置
- $outTradeNo = $this->generateOutTradeNo();
- $config = $this->generateWxPayConfig($order, $outTradeNo);
- // 更新订单号(使用 order_no 而不是 out_trade_no)
- $order->order_no = $outTradeNo;
- $order->save();
- // 发送抢单通知
- $this->sendGrabOrderNotification($order);
- return $config;
- }
- /**
- * 生成外部交易号
- */
- private function generateOutTradeNo()
- {
- return date('YmdHis') . mt_rand(1000, 9999);
- }
- /**
- * 生成微信支付配置
- */
- private function generateWxPayConfig($order, $outTradeNo)
- {
- $appId = config('wechat.official_account.default.app_id');
- // 创建支付订单
- $result = $this->app->getClient()->postJson('v3/pay/transactions/jsapi', [
- 'appid' => $appId,
- 'mchid' => config('wechat.pay.default.mch_id'),
- 'out_trade_no' => $outTradeNo,
- 'description' => "订单支付#{$order->id}",
- 'notify_url' => config('wechat.pay.default.notify_url'),
- 'amount' => [
- 'total' => intval($order->pay_amount * 100), // 单位:分
- 'currency' => 'CNY'
- ],
- 'payer' => [
- 'openid' => $order->member->socialAccounts()
- ->where('platform', 'WECHAT')
- ->value('social_id')
- ],
- ]);
- // 获取预支付交易会话标识
- $prepayId = $result['prepay_id'];
- // 使用 EasyWeChat 的工具方法生成支付配置
- $config = $this->app->getUtils()->buildBridgeConfig($prepayId, false);
- // 确保 appId 存在
- $config['appId'] = $appId;
- return $config;
- }
- /**
- * 发送抢单通知
- */
- private function sendGrabOrderNotification($order)
- {
- // TODO: 对接极光推送,发送抢单通知
- }
- /**
- * 处理支付结果
- */
- private function handlePaymentResult(array $data): bool
- {
- // 1. 校验订单金额
- $order = Order::where('order_no', $data['out_trade_no'])->first();
- if (!$order || $order->amount !== ($data['amount']['total'] / 100)) {
- throw new \Exception('订单金额不匹配');
- }
- // 2. 更新订单状态
- if ($data['trade_state'] === 'SUCCESS') {
- return DB::transaction(function () use ($order, $data) {
- // 更新订单状态为已支付
- $order->update([
- 'state' => OrderStatus::PAID->value,
- 'payment_time' => now(),
- 'transaction_id' => $data['transaction_id']
- ]);
- // TODO: 其他业务逻辑,如通知技师等
- return true;
- });
- }
- return false;
- }
- /**
- * [微信]处理支付回调通知
- */
- public function handleNotify(Request $request)
- {
- try {
- // 获取支付通知并处理
- return $this->app->getServer()->handlePaid(function (Message $message) {
- try {
- // 处理支付结果
- return $this->handlePaymentResult([
- 'out_trade_no' => $message->out_trade_no,
- 'transaction_id' => $message->transaction_id,
- 'trade_state' => $message->trade_state,
- 'amount' => [
- 'total' => $message->amount->total,
- ],
- ]);
- } catch (\Exception $e) {
- Log::error('支付结果处理失败', [
- 'error' => $e->getMessage(),
- 'trace' => $e->getTraceAsString()
- ]);
- return false;
- }
- });
- } catch (\Exception $e) {
- Log::error('微信支付回调处理失败', [
- 'error' => $e->getMessage(),
- 'trace' => $e->getTraceAsString()
- ]);
- return response()->json([
- 'code' => 'FAIL',
- 'message' => '处理失败'
- ]);
- }
- }
- }
|