Compare commits
No commits in common. "81cb53736d1ce2f3f999810a1f4645f3dafacdea" and "e1a989b2a676e00ac5a535cf137578313d5253e7" have entirely different histories.
81cb53736d
...
e1a989b2a6
|
|
@ -2,13 +2,7 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Enums\PaymentStatus;
|
|
||||||
use App\Enums\PaymentMethod;
|
|
||||||
use App\Models\Invoice;
|
|
||||||
use App\Models\Payment;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Stripe\Stripe;
|
use Stripe\Stripe;
|
||||||
use Stripe\Webhook;
|
|
||||||
|
|
||||||
class StripeController extends Controller
|
class StripeController extends Controller
|
||||||
{
|
{
|
||||||
|
|
@ -17,83 +11,7 @@ class StripeController extends Controller
|
||||||
return view('stripe.index');
|
return view('stripe.index');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkout(Invoice $invoice)
|
public function checkout()
|
||||||
{
|
|
||||||
Stripe::setApiKey(config('services.stripe.secret'));
|
|
||||||
|
|
||||||
$session = \Stripe\Checkout\Session::create([
|
|
||||||
'payment_method_types' => ['card'],
|
|
||||||
'line_items' => [
|
|
||||||
[
|
|
||||||
'price_data' => [
|
|
||||||
'currency' => 'usd',
|
|
||||||
'product_data' => [
|
|
||||||
'name' => "Invoice {$invoice->invoice_number}",
|
|
||||||
],
|
|
||||||
'unit_amount' => (int) ($invoice->balance_due * 100),
|
|
||||||
],
|
|
||||||
'quantity' => 1,
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'mode' => 'payment',
|
|
||||||
'success_url' => route('stripe.success', $invoice),
|
|
||||||
'cancel_url' => route('invoices.show', $invoice),
|
|
||||||
'metadata' => [
|
|
||||||
'invoice_id' => $invoice->id,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
return redirect($session->url);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function webhook(Request $request)
|
|
||||||
{
|
|
||||||
$payload = $request->getContent();
|
|
||||||
$signature = $request->header('Stripe-Signature');
|
|
||||||
|
|
||||||
try {
|
|
||||||
$event = \Stripe\Webhook::constructEvent(
|
|
||||||
$payload,
|
|
||||||
$signature,
|
|
||||||
config('services.stripe.webhook_secret')
|
|
||||||
);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return response('Invalid signature', 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($event->type === 'checkout.session.completed') {
|
|
||||||
$session = $event->data->object;
|
|
||||||
|
|
||||||
$invoice = Invoice::find($session->metadata->invoice_id);
|
|
||||||
|
|
||||||
if ($invoice) {
|
|
||||||
Stripe::setApiKey(config('services.stripe.secret'));
|
|
||||||
|
|
||||||
// Retrieve PaymentIntent with expanded charge and balance_transaction
|
|
||||||
$paymentIntent = \Stripe\PaymentIntent::retrieve([
|
|
||||||
'id' => $session->payment_intent,
|
|
||||||
'expand' => ['latest_charge.balance_transaction'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$feeAmount = $paymentIntent->latest_charge->balance_transaction->fee;
|
|
||||||
|
|
||||||
Payment::create([
|
|
||||||
'invoice_id' => $invoice->id,
|
|
||||||
'payment_date' => now(),
|
|
||||||
'status' => PaymentStatus::COMPLETED,
|
|
||||||
'payment_method' => PaymentMethod::CARD,
|
|
||||||
'reference' => $session->payment_intent,
|
|
||||||
'stripe_payment_intent_id' => $session->payment_intent,
|
|
||||||
'amount' => $session->amount_total / 100,
|
|
||||||
'fee_amount' => $feeAmount / 100,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response('OK', 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function checkoutTutorial()
|
|
||||||
{
|
{
|
||||||
Stripe::setApiKey(config('stripe.sk'));
|
Stripe::setApiKey(config('stripe.sk'));
|
||||||
|
|
||||||
|
|
@ -118,8 +36,8 @@ class StripeController extends Controller
|
||||||
return redirect()->away($session->url);
|
return redirect()->away($session->url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function success(Invoice $invoice)
|
public function success()
|
||||||
{
|
{
|
||||||
return view('stripe.success', compact('invoice'));
|
return view('stripe.index');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,8 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||||
health: '/up',
|
health: '/up',
|
||||||
)
|
)
|
||||||
->withMiddleware(function (Middleware $middleware): void {
|
->withMiddleware(function (Middleware $middleware): void {
|
||||||
$middleware->validateCsrfTokens(except: [
|
//
|
||||||
'stripe/webhook',
|
|
||||||
]);
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
->withExceptions(function (Exceptions $exceptions): void {
|
->withExceptions(function (Exceptions $exceptions): void {
|
||||||
//
|
//
|
||||||
})->create();
|
})->create();
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,4 @@ return [
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
'stripe' => [
|
|
||||||
'secret' => env('STRIPE_SK'),
|
|
||||||
'webhook_secret' => env('STRIPE_WEBHOOK_SECRET'),
|
|
||||||
],
|
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -137,34 +137,13 @@
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if($invoice->balance_due != 0)
|
@if($invoice->balance_due != 0)
|
||||||
<div class="mb-12 p-6 bg-gray-50 rounded-lg">
|
<div class="mb-12 p-4 bg-gray-50 rounded">
|
||||||
<h2 class="text-sm font-semibold text-gray-500 uppercase mb-4">Payment Options</h2>
|
<h2 class="text-sm font-semibold text-gray-500 uppercase mb-2">Payment</h2>
|
||||||
|
<p class="text-gray-700">Please make payment to:</p>
|
||||||
<div class="flex flex-col md:flex-row gap-6">
|
<p class="text-gray-800 font-medium mt-1">eBandroom</p>
|
||||||
<div class="flex-1">
|
|
||||||
<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">540 W. Louse Ave.</p>
|
||||||
<p class="text-gray-600">Vinita, OK 74301</p>
|
<p class="text-gray-600">Vinita, OK 74301</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if($invoice->notes)
|
@if($invoice->notes)
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
<!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>
|
|
||||||
|
|
@ -17,14 +17,13 @@ Route::middleware(['auth', 'verified'])->group(function () {
|
||||||
Route::view('invoices', 'invoices.index')->name('invoices');
|
Route::view('invoices', 'invoices.index')->name('invoices');
|
||||||
Route::get('invoices/{invoice}/edit',
|
Route::get('invoices/{invoice}/edit',
|
||||||
fn(Invoice $invoice) => view('invoices.edit', compact('invoice')))->name('invoices.edit');
|
fn(Invoice $invoice) => view('invoices.edit', compact('invoice')))->name('invoices.edit');
|
||||||
|
Route::get('invoices/{invoice}', CustomerInvoiceController::class)->name('invoices.show');
|
||||||
Route::view('payments', 'payments.index')->name('payments');
|
Route::view('payments', 'payments.index')->name('payments');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::get('invoices/{invoice}', CustomerInvoiceController::class)->name('invoices.show');
|
// Testing Stripe
|
||||||
|
|
||||||
// Stripe
|
|
||||||
Route::get('stripe', [StripeController::class, 'index'])->name('stripe.index');
|
Route::get('stripe', [StripeController::class, 'index'])->name('stripe.index');
|
||||||
Route::post('/stripe/checkout/{invoice}', [StripeController::class, 'checkout'])->name('stripe.checkout');
|
Route::post('/checkout ', [StripeController::class, 'checkout'])->name('stripe.checkout');
|
||||||
Route::get('/stripe/success/{invoice}', [StripeController::class, 'success'])->name('stripe.success');
|
Route::get('/success', [StripeController::class, 'success'])->name('stripe.success');
|
||||||
Route::post('stripe/webhook', [StripeController::class, 'webhook'])->name('stripe.webhook');
|
|
||||||
require __DIR__.'/settings.php';
|
require __DIR__.'/settings.php';
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue