ldc-boutique-cnc-sable/app/Http/Controllers/Fo/TunnelController.php
2026-10-27 09:58:12 +01:00

176 lines
5.2 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Controllers\Fo;
use App\Http\Controllers\Controller;
use App\Http\Requests\Fo\Orders\PickTimeSlotRequest;
use App\Http\Requests\Fo\Orders\ValidateSummaryRequest;
use App\Models\Order;
use App\Services\MapUrlService;
use Domain\Enums\OrderTunnelStep;
use Domain\Exceptions\OrderTunnel\OrderLimitExceededException;
use Domain\Exceptions\OrderTunnel\WeeklyLimitExceededException;
use Domain\Ports\Repositories\ShopRepository;
use Domain\Services\BasketService;
use Domain\Services\OrderTunnelService;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Infrastructure\Adapters\Services\AppCustomerAuthService;
class TunnelController extends Controller
{
public function __construct(
private readonly AppCustomerAuthService $authService,
private readonly BasketService $basketService,
private readonly OrderTunnelService $orderTunnelService,
private readonly MapUrlService $mapUrlService,
private readonly ShopRepository $shopRepository,
) {
}
// * -- STEP 1 -- *
public function basketSummary(BasketService $basketService): View
{
$this->authorize('canReviewBasketSummary', OrderTunnelStep::class);
$step = OrderTunnelStep::REVIEW;
$basket = $basketService->getBasket();
return view('fo.tunnel.basket-summary', compact(
'step',
'basket'
));
}
public function basketSummarySubmit(ValidateSummaryRequest $request): RedirectResponse
{
$this->authorize('canReviewBasketSummary', OrderTunnelStep::class);
$customer = $this->authService->getCustomerAsMandatory();
$basket = $this->basketService->getBasket();
$this->orderTunnelService->initializeFromBasket(
$basket,
$customer->getId()
);
return to_route('fo.sales.pick-time-slot');
}
// * -- STEP 2 -- *
public function pickTimeSlot(): View
{
$this->authorize('canPickTimeSlot', OrderTunnelStep::class);
$customer = $this->authService->getCustomerAsMandatory();
$shop = $this->orderTunnelService->getShopForCustomer($customer->getId());
$timeSlots = $this->orderTunnelService->getAvailableTimeSlots($shop);
$step = OrderTunnelStep::BOOKING;
$mapUrl = $this->mapUrlService->generateUrl($shop);
return view('fo.tunnel.pick-time-slot', compact(
'step',
'shop',
'mapUrl',
'timeSlots'
));
}
public function pickTimeSlotSubmit(PickTimeSlotRequest $request): RedirectResponse
{
$this->authorize('canPickTimeSlot', OrderTunnelStep::class);
$customer = $this->authService->getCustomerAsMandatory();
$builder = $this->orderTunnelService->getBuilderFromBasketOrFail();
$shop = $this->orderTunnelService->getShopForCustomer($customer->getId());
$timeSlots = $this->orderTunnelService->getAvailableTimeSlots($shop);
$matchedSlot = $this->orderTunnelService->applyTimeSlot(
$builder,
$shop,
$request->getTimeslot(),
$timeSlots
);
if ($matchedSlot === null) {
return back()->withErrors([
'timeslot' => trans('Invalid or unavailable time slot'),
])->withInput();
}
return to_route('fo.sales.confirmation');
}
// * -- STEP 3 -- *
public function confirmation(): View
{
$this->authorize('canFinalizeOrder', OrderTunnelStep::class);
$step = OrderTunnelStep::CONFIRMATION;
$builder = $this->orderTunnelService->getBuilderCompletedOrFail();
$basket = $builder->getBasket();
$shop = $this->shopRepository->find($builder->getShopId());
if (! $shop) {
abort(404, 'Shop not found');
}
return view('fo.tunnel.confirmation', compact(
'step',
'basket',
'builder',
'shop'
));
}
public function confirmationSubmit(Request $request): RedirectResponse
{
$this->authorize('canFinalizeOrder', OrderTunnelStep::class);
$request->validate([
'ok_cgv' => ['accepted'],
]);
$builder = $this->orderTunnelService->getBuilderCompletedOrFail();
try {
$order = $this->orderTunnelService->finalizeOrder($builder);
} catch (WeeklyLimitExceededException | OrderLimitExceededException $e) {
return back()->with('message', $e->getMessage());
}
return to_route('fo.sales.confirmation.show-confirmed', $order->reference->value);
}
// * -- CONFIRMATION -- *
public function confirmed(Order $order): View
{
$this->authorize('viewOwn', $order);
$step = OrderTunnelStep::CONFIRMATION;
$shop = $order->shop;
if (! $shop) {
throw new \UnexpectedValueException('Shop not found for order ' . $order->getId());
}
$mapUrl = $this->mapUrlService->generateUrl($shop);
return view('fo.tunnel.confirmed', compact(
'step',
'order',
'shop',
'mapUrl'
));
}
}