175 lines
6.0 KiB
PHP
175 lines
6.0 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Shop;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Order;
|
|
use App\Models\OrderItem;
|
|
use App\Models\Product;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class CheckoutController extends Controller
|
|
{
|
|
private const CHECKOUT_CUSTOMER_KEY = 'checkout.customer';
|
|
|
|
public function show(Request $request)
|
|
{
|
|
$items = $this->cartItems($request);
|
|
|
|
if ($items->isEmpty()) {
|
|
return redirect()->route('cart.index')->with('status', 'Корзина пустая. Добавьте товары перед оформлением.');
|
|
}
|
|
|
|
return view('shop.checkout', [
|
|
'items' => $items,
|
|
'total' => $items->sum('subtotal'),
|
|
'itemsCount' => $items->sum('quantity'),
|
|
]);
|
|
}
|
|
|
|
public function prepare(Request $request)
|
|
{
|
|
$items = $this->cartItems($request);
|
|
|
|
if ($items->isEmpty()) {
|
|
return redirect()->route('cart.index')->with('status', 'Корзина пустая. Добавьте товары перед оформлением.');
|
|
}
|
|
|
|
$validated = $request->validate([
|
|
'customer_name' => ['required', 'string', 'max:255'],
|
|
'email' => ['required', 'email', 'max:255'],
|
|
'phone' => ['nullable', 'string', 'max:50'],
|
|
'address' => ['required', 'string', 'max:500'],
|
|
'comment' => ['nullable', 'string', 'max:1000'],
|
|
]);
|
|
|
|
$validated['payment_method'] = 'card_transfer';
|
|
$request->session()->put(self::CHECKOUT_CUSTOMER_KEY, $validated);
|
|
|
|
return redirect()->route('checkout.payment');
|
|
}
|
|
|
|
public function payment(Request $request)
|
|
{
|
|
$items = $this->cartItems($request);
|
|
|
|
if ($items->isEmpty()) {
|
|
return redirect()->route('cart.index')->with('status', 'Корзина пустая. Добавьте товары перед оформлением.');
|
|
}
|
|
|
|
$customer = $request->session()->get(self::CHECKOUT_CUSTOMER_KEY);
|
|
if (!is_array($customer)) {
|
|
return redirect()->route('checkout.show')->with('status', 'Сначала заполните данные получателя.');
|
|
}
|
|
|
|
return view('shop.checkout-payment', [
|
|
'items' => $items,
|
|
'total' => $items->sum('subtotal'),
|
|
'itemsCount' => $items->sum('quantity'),
|
|
'customer' => $customer,
|
|
]);
|
|
}
|
|
|
|
public function store(Request $request)
|
|
{
|
|
$items = $this->cartItems($request);
|
|
|
|
if ($items->isEmpty()) {
|
|
return redirect()->route('cart.index')->with('status', 'Корзина пустая. Добавьте товары перед оформлением.');
|
|
}
|
|
|
|
$validated = $request->session()->get(self::CHECKOUT_CUSTOMER_KEY);
|
|
if (!is_array($validated)) {
|
|
return redirect()->route('checkout.show')->with('status', 'Сначала заполните данные получателя.');
|
|
}
|
|
|
|
$validator = validator($validated, [
|
|
'customer_name' => ['required', 'string', 'max:255'],
|
|
'email' => ['required', 'email', 'max:255'],
|
|
'phone' => ['nullable', 'string', 'max:50'],
|
|
'address' => ['required', 'string', 'max:500'],
|
|
'comment' => ['nullable', 'string', 'max:1000'],
|
|
'payment_method' => ['required', 'string', Rule::in(['card_transfer'])],
|
|
]);
|
|
$validated = $validator->validate();
|
|
|
|
$order = DB::transaction(function () use ($request, $items, $validated) {
|
|
$order = Order::create([
|
|
'user_id' => optional($request->user())->id,
|
|
'status' => 'new',
|
|
'payment_method' => $validated['payment_method'],
|
|
'total' => $items->sum('subtotal'),
|
|
'items_count' => $items->sum('quantity'),
|
|
'customer_name' => $validated['customer_name'],
|
|
'email' => $validated['email'],
|
|
'phone' => $validated['phone'] ?? null,
|
|
'address' => $validated['address'],
|
|
'comment' => $validated['comment'] ?? null,
|
|
]);
|
|
|
|
$rows = $items->map(function (array $item) use ($order) {
|
|
return [
|
|
'order_id' => $order->id,
|
|
'product_id' => $item['product']->id,
|
|
'name' => $item['product']->name,
|
|
'price' => $item['product']->price,
|
|
'quantity' => $item['quantity'],
|
|
'subtotal' => $item['subtotal'],
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
];
|
|
})->all();
|
|
|
|
OrderItem::insert($rows);
|
|
|
|
return $order;
|
|
});
|
|
|
|
$request->session()->forget('cart');
|
|
$request->session()->forget(self::CHECKOUT_CUSTOMER_KEY);
|
|
|
|
return redirect()->route('checkout.success', $order);
|
|
}
|
|
|
|
public function success(Order $order)
|
|
{
|
|
return view('shop.checkout-success', [
|
|
'order' => $order,
|
|
]);
|
|
}
|
|
|
|
private function cartItems(Request $request)
|
|
{
|
|
$cart = (array) $request->session()->get('cart', []);
|
|
|
|
$products = Product::query()
|
|
->whereIn('id', array_keys($cart))
|
|
->where('is_active', true)
|
|
->get()
|
|
->keyBy('id');
|
|
|
|
return collect($cart)
|
|
->map(function ($quantity, $productId) use ($products) {
|
|
$product = $products->get((int) $productId);
|
|
if (!$product) {
|
|
return null;
|
|
}
|
|
|
|
$qty = max(1, min((int) $quantity, (int) $product->stock));
|
|
if ($qty < 1) {
|
|
return null;
|
|
}
|
|
|
|
return [
|
|
'product' => $product,
|
|
'quantity' => $qty,
|
|
'subtotal' => (float) $product->price * $qty,
|
|
];
|
|
})
|
|
->filter()
|
|
->values();
|
|
}
|
|
}
|