Implementation of Stripe.

This commit is contained in:
Matt Young 2026-01-29 22:38:30 -06:00
parent c1dd36d7fd
commit 81cb53736d
4 changed files with 71 additions and 14 deletions

View File

@ -19,6 +19,8 @@ class StripeController extends Controller
public function checkout(Invoice $invoice) public function checkout(Invoice $invoice)
{ {
Stripe::setApiKey(config('services.stripe.secret'));
$session = \Stripe\Checkout\Session::create([ $session = \Stripe\Checkout\Session::create([
'payment_method_types' => ['card'], 'payment_method_types' => ['card'],
'line_items' => [ 'line_items' => [
@ -28,16 +30,16 @@ class StripeController extends Controller
'product_data' => [ 'product_data' => [
'name' => "Invoice {$invoice->invoice_number}", 'name' => "Invoice {$invoice->invoice_number}",
], ],
'unit_amount' => $invoice->balance_due * 100, // Already in cents from MoneyCast? Check this 'unit_amount' => (int) ($invoice->balance_due * 100),
], ],
'quantity' => 1, 'quantity' => 1,
], ],
], ],
'mode' => 'payment', 'mode' => 'payment',
'success_url' => route('checkout.success', $invoice), 'success_url' => route('stripe.success', $invoice),
'cancel_url' => route('invoice.show', $invoice), 'cancel_url' => route('invoices.show', $invoice),
'metadata' => [ 'metadata' => [
'invoice_id' => $invoice->id, // Used by webhook to find the invoice 'invoice_id' => $invoice->id,
], ],
]); ]);
@ -65,6 +67,8 @@ class StripeController extends Controller
$invoice = Invoice::find($session->metadata->invoice_id); $invoice = Invoice::find($session->metadata->invoice_id);
if ($invoice) { if ($invoice) {
Stripe::setApiKey(config('services.stripe.secret'));
// Retrieve PaymentIntent with expanded charge and balance_transaction // Retrieve PaymentIntent with expanded charge and balance_transaction
$paymentIntent = \Stripe\PaymentIntent::retrieve([ $paymentIntent = \Stripe\PaymentIntent::retrieve([
'id' => $session->payment_intent, 'id' => $session->payment_intent,
@ -114,8 +118,8 @@ class StripeController extends Controller
return redirect()->away($session->url); return redirect()->away($session->url);
} }
public function success() public function success(Invoice $invoice)
{ {
return view('stripe.index'); return view('stripe.success', compact('invoice'));
} }
} }

View File

@ -137,12 +137,33 @@
@endif @endif
@if($invoice->balance_due != 0) @if($invoice->balance_due != 0)
<div class="mb-12 p-4 bg-gray-50 rounded"> <div class="mb-12 p-6 bg-gray-50 rounded-lg">
<h2 class="text-sm font-semibold text-gray-500 uppercase mb-2">Payment</h2> <h2 class="text-sm font-semibold text-gray-500 uppercase mb-4">Payment Options</h2>
<p class="text-gray-700">Please make payment to:</p>
<p class="text-gray-800 font-medium mt-1">eBandroom</p> <div class="flex flex-col md:flex-row gap-6">
<p class="text-gray-600">540 W. Louse Ave.</p> <div class="flex-1">
<p class="text-gray-600">Vinita, OK 74301</p> <h3 class="font-medium text-gray-800 mb-2">Pay Online</h3>
<p class="text-gray-600 text-sm mb-4">Pay securely with your credit or debit card.</p>
<form action="{{ route('stripe.checkout', $invoice) }}" method="POST">
@csrf
<button type="submit"
class="inline-flex items-center px-6 py-3 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 transition-colors">
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"></path>
</svg>
Pay {{ formatMoney($invoice->balance_due) }} Now
</button>
</form>
</div>
<div class="flex-1">
<h3 class="font-medium text-gray-800 mb-2">Pay by Mail</h3>
<p class="text-gray-600 text-sm mb-2">Make check payable to:</p>
<p class="text-gray-800 font-medium">eBandroom</p>
<p class="text-gray-600">540 W. Louse Ave.</p>
<p class="text-gray-600">Vinita, OK 74301</p>
</div>
</div>
</div> </div>
@endif @endif

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Payment Received - Invoice {{ $invoice->invoice_number }}</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-50 min-h-screen flex items-center justify-center p-8">
<div class="bg-white rounded-lg shadow-lg p-8 max-w-md w-full text-center">
<div class="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-6">
<svg class="w-8 h-8 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
</svg>
</div>
<h1 class="text-2xl font-bold text-gray-800 mb-2">Payment Received</h1>
<p class="text-gray-600 mb-6">Thank you for your payment.</p>
<div class="bg-gray-50 rounded-lg p-4 mb-6">
<p class="text-sm text-gray-500">Invoice</p>
<p class="text-lg font-semibold text-gray-800">{{ $invoice->invoice_number }}</p>
<p class="text-sm text-gray-500 mt-2">{{ $invoice->client->name }}</p>
</div>
<a href="{{ route('invoices.show', $invoice) }}"
class="inline-block bg-blue-600 text-white px-6 py-3 rounded-lg font-medium hover:bg-blue-700 transition-colors">
View Invoice
</a>
</div>
</body>
</html>

View File

@ -24,7 +24,7 @@ Route::get('invoices/{invoice}', CustomerInvoiceController::class)->name('invoic
// Stripe // Stripe
Route::get('stripe', [StripeController::class, 'index'])->name('stripe.index'); Route::get('stripe', [StripeController::class, 'index'])->name('stripe.index');
Route::post('/stripe/checkout ', [StripeController::class, 'checkout'])->name('stripe.checkout'); Route::post('/stripe/checkout/{invoice}', [StripeController::class, 'checkout'])->name('stripe.checkout');
Route::get('/success', [StripeController::class, 'success'])->name('stripe.success'); Route::get('/stripe/success/{invoice}', [StripeController::class, 'success'])->name('stripe.success');
Route::post('stripe/webhook', [StripeController::class, 'webhook'])->name('stripe.webhook'); Route::post('stripe/webhook', [StripeController::class, 'webhook'])->name('stripe.webhook');
require __DIR__.'/settings.php'; require __DIR__.'/settings.php';