diff --git a/src/app/Catalogue/MenuRepository.php b/src/app/Catalogue/MenuRepository.php index 83c0b38..16754c6 100644 --- a/src/app/Catalogue/MenuRepository.php +++ b/src/app/Catalogue/MenuRepository.php @@ -147,6 +147,23 @@ final class MenuRepository return $this->db->fetch('SELECT id FROM product WHERE id = :id', ['id' => $id]) !== null; } + /** + * Le produit existe-t-il ET est-il un produit de BASE (base_product_id IS NULL, + * R4) ? Garde serveur de l'eligibilite au menu (F9-2) : un menu ne peut prendre + * comme burger principal NI comme option de slot une VARIANTE de taille (ex. + * "Coca Cola 50cl"), qui n'est pas un produit autonome. Predicat plus strict que + * productExists() : il rejette une variante meme si l'UI est contournee. Le + * formulaire menu n'expose deja que des bases (ProductRepository::basesOnly), + * cette garde verrouille le chemin serveur en plus. + */ + public function productIsBase(int $id): bool + { + return $this->db->fetch( + 'SELECT id FROM product WHERE id = :id AND base_product_id IS NULL', + ['id' => $id], + ) !== null; + } + /** * Pre-verification FK-safe (mlt 8.6 RG-1) : le menu est-il reference par une * ligne de commande historique ? La FK order_item.menu_id est RESTRICT. diff --git a/src/app/Catalogue/ProductRepository.php b/src/app/Catalogue/ProductRepository.php index 0029b1b..570b855 100644 --- a/src/app/Catalogue/ProductRepository.php +++ b/src/app/Catalogue/ProductRepository.php @@ -28,7 +28,16 @@ final class ProductRepository } /** - * Liste pour le back-office, avec le libelle de categorie. + * Liste pour le back-office, avec le libelle de categorie et, pour une VARIANTE + * de taille (base_product_id non nul, R4), le nom de sa base. La liste admin + * affiche AINSI toutes les lignes produit -- bases ET variantes -- mais marque + * chaque variante "Variante de X" : l'admin la voit, comprend qu'elle n'est pas + * un produit autonome, et peut la delier/relier via le formulaire. La projection + * remonte base_product_id pour que la vue distingue les deux. + * + * Cette methode N'ALIMENTE PLUS les selects du formulaire menu (qui doivent etre + * base-only, R4/F9-1) : ceux-ci passent par basesOnly(). all() peut donc porter + * le LEFT JOIN d'enrichissement sans fausser une liste deroulante. * * @return array> */ @@ -36,12 +45,34 @@ final class ProductRepository { return $this->db->fetchAll( 'SELECT p.id, p.category_id, p.name, p.price_cents, p.vat_rate, p.is_available, ' - . 'p.display_order, c.name AS category_name ' + . 'p.display_order, p.size_cl, p.base_product_id, c.name AS category_name, ' + . 'b.name AS base_name ' . 'FROM product p JOIN category c ON c.id = p.category_id ' + . 'LEFT JOIN product b ON b.id = p.base_product_id ' . 'ORDER BY p.display_order, p.name', ); } + /** + * Produits de BASE uniquement (base_product_id IS NULL, R4), pour alimenter les + * listes deroulantes du formulaire menu (burger principal + options de slot, + * F9-1) et le select base_product_id du formulaire produit. Une VARIANTE de + * taille (ex. "Coca Cola 50cl") n'est jamais un produit autonome : la proposer + * comme burger/option/base ferait apparaitre la variante comme un produit a part + * entiere. Le predicat anti-variante vit ici (cote requete), miroir de la garde + * serveur MenuRepository::productIsBase(). Projection minimale {id, name} : seules + * colonnes utiles a un