* 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 $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 $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']); } }