[Back] <?php
namespace App\Http\Controllers;
use App\Models\{Cart, Order, OrderItem, Payment};
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class CheckoutController extends Controller
{
private function userCart(): Cart
{
return Cart::firstOrCreate(['user_id' => auth()->id()]);
}
public function show()
{
$cart = $this->userCart()->load('items.product');
abort_if($cart->items->isEmpty(), 404);
$subtotalCents = $cart->items->sum(fn($i) => $i->quantity * $i->unit_price_cents);
return view('checkout.show', compact('cart', 'subtotalCents'));
}
public function placeOrder(Request $request)
{
$cart = $this->userCart()->load('items.product');
abort_if($cart->items->isEmpty(), 404);
$validated = $request->validate([
'customer_name' => ['required','string','max:100'],
'customer_phone' => ['required','string','max:30'],
'address_line1' => ['required','string','max:200'],
'address_line2' => ['nullable','string','max:200'],
'city' => ['required','string','max:100'],
'state' => ['required','string','max:100'],
'postcode' => ['required','string','max:20'],
'country' => ['required','string','max:2'],
]);
$user = auth()->user();
$user->customerProfile()->updateOrCreate(
['user_id' => $user->id],
[
'phone' => $validated['customer_phone'],
'address_line1' => $validated['address_line1'],
'address_line2' => $validated['address_line2'] ?? null,
'city' => $validated['city'],
'state' => $validated['state'],
'postcode' => $validated['postcode'],
'country' => $validated['country'],
]
);
$subtotalCents = $cart->items->sum(fn($i) => $i->quantity * $i->unit_price_cents);
$order = Order::create([
'user_id' => auth()->id(),
'order_no' => 'ORD-' . strtoupper(Str::random(10)),
'subtotal_cents' => $subtotalCents,
'total_cents' => $subtotalCents,
'status' => 'payment_pending',
'customer_name' => $validated['customer_name'],
'customer_phone' => $validated['customer_phone'],
]);
foreach ($cart->items as $item) {
OrderItem::create([
'order_id' => $order->id,
'product_id' => $item->product_id,
'quantity' => $item->quantity,
'unit_price_cents' => $item->unit_price_cents,
'line_total_cents' => $item->quantity * $item->unit_price_cents,
]);
}
$payment = Payment::create([
'order_id' => $order->id,
'provider' => 'fpx',
'status' => 'initiated',
'reference' => null,
'payload' => [
'note' => 'FPX not integrated yet. Add credentials later in config/fpx.php',
],
]);
// Clear cart
$cart->items()->delete();
// For now redirect to placeholder "FPX redirect" page/route
return redirect()->route('payments.fpx.redirect', $order);
}
// Placeholder: in real FPX this would generate payload + redirect user to FPX
public function fpxRedirect(Order $order)
{
abort_unless($order->user_id === auth()->id(), 403);
return view('payments.fpx_redirect', [
'order' => $order,
'fpxConfig' => config('fpx'),
]);
}
// Placeholder callback endpoint
public function fpxCallback(Request $request)
{
// Later: verify signature, update payment + order status
return response()->json([
'message' => 'FPX callback received (stub).',
'data' => $request->all(),
]);
}
}