corentin_wakdo/src/app/Controllers/OrderAdminController.php
Imugiii 425a37f113
All checks were successful
CI / secret-scan (push) Successful in 10s
CI / php-lint (push) Successful in 21s
CI / static-tests (push) Successful in 48s
CI / js-tests (push) Successful in 24s
feat(orders): KDS cuisine + transition paid vers delivered (P3 operationnel)
2026-06-22 07:15:01 +00:00

103 lines
3.2 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Controllers;
use App\Auth\Csrf;
use App\Auth\GuardResult;
use App\Catalogue\MenuRepository;
use App\Catalogue\ProductRepository;
use App\Core\Response;
use App\Order\OrderQueryRepository;
use App\Order\OrderRepository;
use App\Order\OrderValidationException;
/**
* Domaine commande back-office (P4 + P3 operationnel). GET /admin/orders : liste
* recente (order.read). POST /admin/orders/{number}/deliver : transition paid ->
* delivered (DELIVER_ORDER, geste unique, order.deliver), NON PIN-gated. L'annulation
* (CANCEL_ORDER, PIN + restock) et la file cuisine (KitchenController) sont traitees
* ailleurs.
*
* Non `final` : les tests sous-classent (seam db()/orderQuery()/orders()).
*/
class OrderAdminController extends AdminController
{
/**
* @param array<string, string> $params
*/
public function index(array $params = []): Response
{
$guard = $this->guard('order.read');
if ($guard instanceof Response) {
return $guard;
}
return $this->adminView('admin/orders/index', [
'title' => 'Commandes - Wakdo Admin',
'activeNav' => 'orders',
'orders' => $this->orderQuery()->recent(50),
'canDeliver' => $this->may($guard, 'order.deliver'),
], $guard);
}
/**
* Remise au client : paid -> delivered (mlt 6.1). POST + CSRF, garde order.deliver.
* Pas de PIN (geste routinier). Issue affichee en flash, retour a la liste.
*
* @param array<string, string> $params
*/
public function deliver(array $params = []): Response
{
$guard = $this->guard('order.deliver');
if ($guard instanceof Response) {
return $guard;
}
$form = $this->request->formBody();
if (!Csrf::validate($this->sessionManager(), $form['_csrf'] ?? null)) {
return $this->invalidCsrf();
}
try {
$this->orders()->deliver((string) ($params['number'] ?? ''));
$this->setFlash('Commande remise (livree).');
} catch (OrderValidationException $exception) {
$this->setFlash(
$exception->getMessage() === 'ORDER_NOT_FOUND'
? 'Commande introuvable.'
: 'Transition invalide : la commande n\'est pas au statut paye.',
);
}
return $this->redirect('/admin/orders');
}
protected function orderQuery(): OrderQueryRepository
{
return new OrderQueryRepository($this->db());
}
protected function orders(): OrderRepository
{
$db = $this->db();
return new OrderRepository($db, new ProductRepository($db), new MenuRepository($db));
}
private function may(GuardResult $guard, string $permission): bool
{
return $this->authorizer()->can($guard->roleId ?? 0, $permission);
}
private function redirect(string $location): Response
{
return Response::make('', 302, ['Location' => $location]);
}
private function invalidCsrf(): Response
{
return Response::make('Requete invalide.', 403, ['Content-Type' => 'text/plain; charset=utf-8']);
}
}