PaymentService.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. <?php
  2. namespace App\Services\Client;
  3. use App\Models\Order;
  4. use App\Enums\OrderStatus;
  5. use App\Enums\UserStatus;
  6. use App\Models\MemberUser;
  7. use EasyWeChat\Pay\Message;
  8. use Illuminate\Http\Request;
  9. use Illuminate\Support\Facades\DB;
  10. use Illuminate\Support\Facades\Log;
  11. use Illuminate\Support\Facades\Auth;
  12. use EasyWeChat\Pay\Application;
  13. class PaymentService
  14. {
  15. private Application $app;
  16. public function __construct()
  17. {
  18. $this->app = new Application(config('wechat.pay.default'));
  19. }
  20. /**
  21. * [微信]获取支付配置
  22. *
  23. * @param int $orderId 订单编号
  24. * @return array
  25. * @throws Exception
  26. */
  27. public function getPaymentConfig($orderId)
  28. {
  29. // 获取当前用户
  30. $userId = Auth::id();
  31. $user = MemberUser::where('state', UserStatus::OPEN->value)->findOrFail($userId);
  32. // 查询订单
  33. $order = Order::where('id', $orderId)
  34. ->where('user_id', $userId)
  35. ->where('state', OrderStatus::CREATED->value)
  36. ->firstOrFail();
  37. // 生成微信支付配置
  38. $outTradeNo = $this->generateOutTradeNo();
  39. $config = $this->generateWxPayConfig($order, $outTradeNo);
  40. // 更新订单号(使用 order_no 而不是 out_trade_no)
  41. $order->order_no = $outTradeNo;
  42. $order->save();
  43. // 发送抢单通知
  44. $this->sendGrabOrderNotification($order);
  45. return $config;
  46. }
  47. /**
  48. * 生成外部交易号
  49. */
  50. private function generateOutTradeNo()
  51. {
  52. return date('YmdHis') . mt_rand(1000, 9999);
  53. }
  54. /**
  55. * 生成微信支付配置
  56. */
  57. private function generateWxPayConfig($order, $outTradeNo)
  58. {
  59. $appId = config('wechat.official_account.default.app_id');
  60. // 创建支付订单
  61. $result = $this->app->getClient()->postJson('v3/pay/transactions/jsapi', [
  62. 'appid' => $appId,
  63. 'mchid' => config('wechat.pay.default.mch_id'),
  64. 'out_trade_no' => $outTradeNo,
  65. 'description' => "订单支付#{$order->id}",
  66. 'notify_url' => config('wechat.pay.default.notify_url'),
  67. 'amount' => [
  68. 'total' => intval($order->pay_amount * 100), // 单位:分
  69. 'currency' => 'CNY'
  70. ],
  71. 'payer' => [
  72. 'openid' => $order->member->socialAccounts()
  73. ->where('platform', 'WECHAT')
  74. ->value('social_id')
  75. ],
  76. ]);
  77. // 获取预支付交易会话标识
  78. $prepayId = $result['prepay_id'];
  79. // 使用 EasyWeChat 的工具方法生成支付配置
  80. $config = $this->app->getUtils()->buildBridgeConfig($prepayId, false);
  81. // 确保 appId 存在
  82. $config['appId'] = $appId;
  83. return $config;
  84. }
  85. /**
  86. * 发送抢单通知
  87. */
  88. private function sendGrabOrderNotification($order)
  89. {
  90. // TODO: 对接极光推送,发送抢单通知
  91. }
  92. /**
  93. * 处理支付结果
  94. */
  95. private function handlePaymentResult(array $data): bool
  96. {
  97. // 1. 校验订单金额
  98. $order = Order::where('order_no', $data['out_trade_no'])->first();
  99. if (!$order || $order->amount !== ($data['amount']['total'] / 100)) {
  100. throw new \Exception('订单金额不匹配');
  101. }
  102. // 2. 更新订单状态
  103. if ($data['trade_state'] === 'SUCCESS') {
  104. return DB::transaction(function () use ($order, $data) {
  105. // 更新订单状态为已支付
  106. $order->update([
  107. 'state' => OrderStatus::PAID->value,
  108. 'payment_time' => now(),
  109. 'transaction_id' => $data['transaction_id']
  110. ]);
  111. // TODO: 其他业务逻辑,如通知技师等
  112. return true;
  113. });
  114. }
  115. return false;
  116. }
  117. /**
  118. * [微信]处理支付回调通知
  119. */
  120. public function handleNotify(Request $request)
  121. {
  122. try {
  123. // 获取支付通知并处理
  124. return $this->app->getServer()->handlePaid(function (Message $message) {
  125. try {
  126. // 处理支付结果
  127. return $this->handlePaymentResult([
  128. 'out_trade_no' => $message->out_trade_no,
  129. 'transaction_id' => $message->transaction_id,
  130. 'trade_state' => $message->trade_state,
  131. 'amount' => [
  132. 'total' => $message->amount->total,
  133. ],
  134. ]);
  135. } catch (\Exception $e) {
  136. Log::error('支付结果处理失败', [
  137. 'error' => $e->getMessage(),
  138. 'trace' => $e->getTraceAsString()
  139. ]);
  140. return false;
  141. }
  142. });
  143. } catch (\Exception $e) {
  144. Log::error('微信支付回调处理失败', [
  145. 'error' => $e->getMessage(),
  146. 'trace' => $e->getTraceAsString()
  147. ]);
  148. return response()->json([
  149. 'code' => 'FAIL',
  150. 'message' => '处理失败'
  151. ]);
  152. }
  153. }
  154. }