如何在 Laravel 中集成 PayPal 高级结账

问题描述 投票:0回答:1

PayPal Advanced Checkout

我想将表格与 PayPal 集成。这意味着,当有人填写表格、选择付款方式并填写付款详细信息时,他们的卡余额将会减少。我不想使用 PayPal 的标准结帐,而是使用高级结帐,以便用户无需拥有 PayPal 帐户即可付款。

我创建了如下代码。

web.php

Route::get('/', function () {
    return view('welcome');
});

Route::post('/create-order', [PaymentController::class, 'createOrder'])->name('create.order');
Route::post('/capture-order', [PaymentController::class, 'captureOrder'])->name('capture.order');

PaymentController.php

<?php

namespace App\Http\Controllers;

use App\Services\PayPalService;
use Illuminate\Http\Request;

class PaymentController extends Controller
{
    private PayPalService $paypal;

    public function __construct(PayPalService $paypal)
    {
        $this->paypal = $paypal;
    }

    public function createOrder(Request $request)
    {
        try {
            $order = $this->paypal->createOrder($request);
            return response()->json($order);
        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 500);
        }
    }

    public function captureOrder(Request $request)
    {
        try {
            $result = $this->paypal->captureOrder($request->orderId);
            return response()->json($result);
        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 500);
        }
    }
}

PayPalService.php

<?php

namespace App\Services;

use App\Models\User;
use App\Models\Order;
use App\Models\Ticket;
use Core\Request\Request;
use Illuminate\Support\Facades\Http;

class PayPalService
{
    private string $clientId;
    private string $secret;
    private string $apiUrl;

    public function __construct()
    {
        $this->clientId = config('services.paypal.client_id');
        $this->secret = config('services.paypal.secret');
        $this->apiUrl = config('services.paypal.api_url');
    }

    private function getAccessToken(): string
    {
        $response = Http::withBasicAuth($this->clientId, $this->secret)
            ->asForm()
            ->post("{$this->apiUrl}/v1/oauth2/token", [
                'grant_type' => 'client_credentials',
            ]);

        if (!$response->successful()) {
            throw new \Exception('Failed to get PayPal access token');
        }

        return $response->json()['access_token'];
    }

    public function createOrder($request)
    {
        $accessToken = $this->getAccessToken();

        $ticket = Ticket::first();

        $user = User::updateOrCreate([
            'email' => $request->email,
        ], [
            'name' => $request->name,
            'email' => $request->email,
            'password' => bcrypt('password'),
        ]);

        $order = Order::create([
            'ticket_id'      => $ticket->id,
            'user_id'        => $user->id,
            'order_code'     => uniqid(),
            'amount'         => $ticket->price,
            'payment_method' => 'paypal',
        ]);

        $response = Http::withToken($accessToken)
            ->post("{$this->apiUrl}/v2/checkout/orders", [
                'intent' => 'CAPTURE',
                'purchase_units' => [[
                    'amount' => [
                        'value' => number_format($ticket->price, 2, '.', ''),
                        'currency_code' => 'USD',
                    ],
                ]],
            ]);

        if (!$response->successful()) {
            throw new \Exception('Failed to create PayPal order');
        }

        return $response->json();
    }

    public function captureOrder($orderId)
    {
        $accessToken = $this->getAccessToken();

        $response = Http::withToken($accessToken)
            ->post("{$this->apiUrl}/v2/checkout/orders/{$orderId}/capture");

        // \Log::info(['captureOrder' => $response]);

        if (!$response->successful()) {
            throw new \Exception('Failed to capture PayPal order');
        }

        return $response->json();
    }
}

welcome.blade.php

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Laravel PayPal</title>
        <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
        <meta name="csrf-token" content="{{ csrf_token() }}">
    </head>
    <body>
        <div class="container">
            <div class="row">
                <div class="col-md-6 offset-md-3">
                    <h1 class="text-center">
                        Laravel PayPal
                    </h1>
                    <div class="card mb-3">
                        <div class="card-body">
                            <div class="mb-3">
                                <label for="name" class="form-label">Full name</label>
                                <input type="text" class="form-control" id="name" name="name">
                            </div>
                            <div class="mb-3">
                                <label for="email" class="form-label">Email address</label>
                                <input type="email" class="form-control" id="email" name="email">
                            </div>
                        </div>
                    </div>
                    <div id="paypal-button"></div>
                </div>
            </div>
        </div>
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
        <script src="https://www.paypal.com/sdk/js?client-id={{ env('PAYPAL_CLIENT_ID') }}&components=buttons"></script>
        <script>
            paypal.Buttons({
                createOrder: async () => {
                    const response = await fetch('{{ route('create.order') }}', {
                        method: 'POST',
                        headers: { 
                            'Content-Type': 'application/json',
                            'X-CSRF-TOKEN': '{{ csrf_token() }}',
                        },
                        body: JSON.stringify(
                            { 
                                name: document.getElementById('name').value,
                                email: document.getElementById('email').value,
                            }
                        )
                    });
            
                    const order = await response.json();
                    return order.id;
                },
                onApprove: async (data) => {
                    const response = await fetch('{{ route('capture.order') }}', {
                        method: 'POST',
                        headers: { 
                            'Content-Type': 'application/json',
                            'X-CSRF-TOKEN': '{{ csrf_token() }}',
                        },
                        body: JSON.stringify({ orderId: data.orderID })
                    });
            
                    const result = await response.json();
                    alert('Payment successful: ' + result.id);
                },
            }).render('#paypal-button');
        </script>
    </body>
</html>

我在访问 capture.order 端点时失败了。我该如何解决这个问题?

error log

php laravel paypal paypal-rest-sdk
1个回答
0
投票
            ->post("{$this->apiUrl}/v2/checkout/orders/{$orderId}/capture");

尝试添加

,""
或其他指定空主体的方式

© www.soinside.com 2019 - 2024. All rights reserved.