1. Go to this page and download the library: Download leonardganyire/paypal library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
use LeonardGanyire\Paypal\PayPalClient;
final class PayPalCheckoutController
{
public function __construct(
private readonly PayPalClient $paypal,
) {}
}
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
final class Payment extends Model
{
protected $fillable = [
'user_id',
'order_id',
'provider',
'provider_reference',
'capture_reference',
'status',
'currency',
'amount',
'provider_payload',
];
protected function casts(): array
{
return [
'amount' => 'decimal:2',
'provider_payload' => 'array',
];
}
}
use App\Http\Controllers\Payments\PayPalCancelController;
use App\Http\Controllers\Payments\PayPalCaptureController;
use App\Http\Controllers\Payments\PayPalOrderController;
use App\Http\Controllers\Payments\PayPalReturnController;
use App\Http\Controllers\Payments\PayPalWebhookController;
use Illuminate\Support\Facades\Route;
Route::middleware('auth')->prefix('payments/paypal')->name('payments.paypal.')->group(function (): void {
Route::post('/orders', [PayPalOrderController::class, 'store'])->name('orders.store');
Route::post('/orders/{payment}/capture', [PayPalCaptureController::class, 'store'])->name('orders.capture');
Route::get('/return/{payment}', PayPalReturnController::class)->name('return');
Route::get('/cancel/{payment}', PayPalCancelController::class)->name('cancel');
});
Route::post('/payments/paypal/webhook', PayPalWebhookController::class)
->name('payments.paypal.webhook');
namespace App\Http\Controllers\Payments;
use App\Models\Order;
use App\Models\Payment;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use LeonardGanyire\Paypal\PayPalClient;
final class PayPalOrderController
{
public function __construct(
private readonly PayPalClient $paypal,
) {}
public function store(Request $request): JsonResponse|RedirectResponse
{
$validated = $request->validate([
'order_id' => ['=> $order->total,
]);
$paypalOrder = $this->paypal->createOrder([
'intent' => 'CAPTURE',
'purchase_units' => [[
'reference_id' => (string) $payment->id,
'description' => "Order {$order->id}",
'amount' => [
'currency_code' => strtoupper($payment->currency),
'value' => number_format((float) $payment->amount, 2, '.', ''),
],
]],
'application_context' => [
'brand_name' => config('app.name'),
'return_url' => route('payments.paypal.return', $payment),
'cancel_url' => route('payments.paypal.cancel', $payment),
'user_action' => 'PAY_NOW',
],
], idempotencyKey: (string) $payment->id);
$payment->update([
'provider_reference' => $paypalOrder['id'] ?? null,
'provider_payload' => $paypalOrder,
]);
$approvalUrl = $this->paypal->approvalUrl($paypalOrder);
abort_if($approvalUrl === null, 502, 'PayPal did not return an approval URL.');
if (($validated['mode'] ?? null) === 'redirect') {
return redirect()->away($approvalUrl);
}
return response()->json([
'payment_id' => $payment->id,
'paypal_order_id' => $paypalOrder['id'],
'approval_url' => $approvalUrl,
]);
}
}
namespace App\Http\Controllers\Payments;
use App\Models\Payment;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use LeonardGanyire\Paypal\Enums\PayPalOrderStatus;
use LeonardGanyire\Paypal\PayPalClient;
final class PayPalReturnController
{
public function __construct(
private readonly PayPalClient $paypal,
) {}
public function __invoke(Request $request, Payment $payment): RedirectResponse
{
abort_unless($request->user()->is($payment->user), 403);
$paypalOrderId = (string) $request->query('token');
abort_unless(
is_string($payment->provider_reference) && $paypalOrderId === $payment->provider_reference,
403,
);
$capture = $this->paypal->captureOrder($paypalOrderId);
$status = PayPalOrderStatus::fromResponse($capture);
if ($status->isCompleted()) {
$payment->update([
'status' => 'paid',
'capture_reference' => PayPalOrderStatus::captureReference($capture),
'provider_payload' => $capture,
]);
// Fulfill the order here: grant access, dispatch shipment, send receipt, etc.
}
return redirect()->route('orders.show', $payment->order);
}
}
namespace App\Http\Controllers\Payments;
use App\Models\Payment;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
final class PayPalCancelController
{
public function __invoke(Request $request, Payment $payment): RedirectResponse
{
abort_unless($request->user()->is($payment->user), 403);
$payment->update(['status' => 'cancelled']);
return redirect()
->route('orders.show', $payment->order)
->with('status', 'PayPal checkout was cancelled.');
}
}
namespace App\Http\Controllers\Payments;
use App\Models\Payment;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use LeonardGanyire\Paypal\Enums\PayPalOrderStatus;
use LeonardGanyire\Paypal\PayPalClient;
final class PayPalCaptureController
{
public function __construct(
private readonly PayPalClient $paypal,
) {}
public function store(Request $request, Payment $payment): JsonResponse
{
abort_unless($request->user()->is($payment->user), 403);
$validated = $request->validate([
'paypal_order_id' => ['s->isCompleted()) {
$payment->update([
'status' => 'paid',
'capture_reference' => PayPalOrderStatus::captureReference($capture),
'provider_payload' => $capture,
]);
// Fulfill the order here.
}
$freshPayment = $payment->fresh();
return response()->json([
'status' => $freshPayment->status,
'payment_id' => $freshPayment->id,
'capture_id' => $freshPayment->capture_reference,
]);
}
}