Stripe.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. <?php
  2. namespace App\Http\Controllers\Gateway;
  3. use App\Models\Payment;
  4. use Auth;
  5. use Exception;
  6. use Illuminate\Http\JsonResponse;
  7. use Illuminate\Http\Request;
  8. use Log;
  9. use Response;
  10. use Stripe\Checkout\Session;
  11. use Stripe\Webhook;
  12. class Stripe extends AbstractPayment
  13. {
  14. public function __construct()
  15. {
  16. \Stripe\Stripe::setApiKey(sysConfig('stripe_secret_key'));
  17. }
  18. public function purchase($request): JsonResponse
  19. {
  20. $payment = $this->creatNewPayment(Auth::id(), $request->input('id'), $request->input('amount'));
  21. $data = $this->getCheckoutSessionData($payment->trade_no, $payment->amount);
  22. try {
  23. $session = Session::create($data);
  24. $url = route('stripe-checkout', ['session_id' => $session->id]);
  25. $payment->update(['url' => $url]);
  26. return Response::json(['status' => 'success', 'url' => $url, 'message' => '创建订单成功!']);
  27. } catch (Exception $e) {
  28. Log::error('【Stripe】错误: '.$e->getMessage());
  29. exit;
  30. }
  31. }
  32. protected function getCheckoutSessionData(string $tradeNo, int $amount): array
  33. {
  34. $unitAmount = $amount * 100;
  35. return [
  36. 'payment_method_types' => ['card'],
  37. 'line_items' => [[
  38. 'price_data' => [
  39. 'currency' => 'usd',
  40. 'product_data' => [
  41. 'name' => sysConfig('subject_name') ?: sysConfig('website_name'),
  42. ],
  43. 'unit_amount' => $unitAmount,
  44. ],
  45. 'quantity' => 1,
  46. ]],
  47. 'mode' => 'payment',
  48. 'success_url' => sysConfig('website_url').'/invoices',
  49. 'cancel_url' => sysConfig('website_url').'/invoices',
  50. 'client_reference_id' => $tradeNo,
  51. 'customer_email' => Auth::getUser()->email,
  52. ];
  53. }
  54. // redirect to Stripe Payment url
  55. public function redirectPage($session_id, request $request)
  56. {
  57. return view('user.stripe-checkout', ['session_id' => $session_id]);
  58. }
  59. // url = '/callback/notify?method=stripe'
  60. public function notify($request): void
  61. {
  62. $sigHeader = $_SERVER['HTTP_STRIPE_SIGNATURE'];
  63. $endpointSecret = sysConfig('stripe_signing_secret');
  64. $event = null;
  65. $payload = @file_get_contents('php://input');
  66. try {
  67. $event = Webhook::constructEvent($payload, $sigHeader, $endpointSecret);
  68. } catch (\UnexpectedValueException $e) {
  69. // Invalid payload
  70. http_response_code(400);
  71. exit();
  72. } catch (\Stripe\Exception\SignatureVerificationException $e) {
  73. // Invalid signature
  74. http_response_code(400);
  75. exit();
  76. }
  77. Log::info('Passed signature verification!');
  78. switch ($event->type) {
  79. case 'checkout.session.completed':
  80. /* @var $session Session */
  81. $session = $event->data->object;
  82. // Check if the order is paid (e.g., from a card payment)
  83. //
  84. // A delayed notification payment will have an `unpaid` status, as
  85. // you're still waiting for funds to be transferred from the customer's
  86. // account.
  87. if ($session->payment_status == 'paid') {
  88. // Fulfill the purchase
  89. $this->fulfillOrder($session);
  90. }
  91. break;
  92. case 'checkout.session.async_payment_succeeded':
  93. $session = $event->data->object;
  94. // Fulfill the purchase
  95. $this->fulfillOrder($session);
  96. break;
  97. case 'checkout.session.async_payment_failed':
  98. $session = $event->data->object;
  99. // Send an email to the customer asking them to retry their order
  100. $this->failedPayment($session);
  101. break;
  102. }
  103. http_response_code(200);
  104. exit();
  105. }
  106. public function fulfillOrder(Session $session)
  107. {
  108. $payment = Payment::whereTradeNo($session->client_reference_id)->first();
  109. if ($payment) {
  110. $payment->order->update(['status' => 2]);
  111. }
  112. }
  113. // 未支付成功则关闭订单
  114. public function failedPayment(Session $session)
  115. {
  116. $payment = Payment::whereTradeNo($session->client_reference_id)->first();
  117. if ($payment) {
  118. $payment->order->update(['status' => -1]);
  119. }
  120. }
  121. }