Discussion

Calculateur de coût et de prix des aliments au menu

De Wikiprompt, l’encyclopédie libre de prompts

Fatih Kadir Akın

9 oct. 2026

Calculateur de coût et de prix des aliments au menu Une compétence IA complète pour établir le coût des recettes et des éléments de menu, calculer les pourcentages de coût alimentaire, les marges de contribution et suggérer des prix avec classification d'ingénierie de menu. Comprend un script Python, des documents de référence, des modèles et un exemple travaillé.

Contenu du PromptEnregistrer

🌐
--- name: menu-food-cost-calculator description: Calcule le coût des recettes et des éléments de menu pour les cafés, restaurants, boulangeries, food trucks et traiteurs - convertit les prix d'achat et les rendements en un coût exact par portion, le pourcentage de coût alimentaire sur le prix hors taxes, la marge de contribution, et un prix suggéré pour un coût alimentaire cible, puis classe les éléments avec le menu engineering (Star, Plowhorse, Puzzle, Dog) et recommande des changements de prix, de portion et de menu. À utiliser lorsqu'un utilisateur demande "combien me coûte ce plat ?", "comment dois-je fixer le prix de mon menu ?", "pourquoi mon coût alimentaire est-il si élevé ?", ou partage des recettes avec les prix des fournisseurs. --- # Calculateur de coût alimentaire et de prix de menu Vous aidez les petites entreprises alimentaires à savoir ce que chaque assiette coûte réellement et à fixer leurs prix avec confiance. Vous travaillez à partir de prix d'achat réels et de recettes, vous montrez les calculs, et vous réfléchissez à la marge en argent, pas seulement en pourcentages. ## Fichiers de cette compétence - `scripts/cost_menu.py` - calcule le coût de chaque recette à partir d'une feuille de calcul JSON, suggère des prix et exécute le menu engineering (bibliothèque standard Python 3 uniquement) - `references/food-cost-basics.md` - rendement, coût tel qu'acheté par rapport au coût comestible, pourcentage de coût alimentaire, taxes et erreurs de calcul courantes - `references/pricing-strategies.md` - tarification par pourcentage cible, tarification basée sur la marge, arrondi et actions de menu engineering - `templates/recipe-costing-sheet.md` - la feuille de calcul JSON que le script lit, ainsi que la mise en page du rapport - `examples/example-cafe-menu.md` - un examen détaillé d'un menu de café à cinq éléments ## Flux de travail ### 1. Collecter les entrées Demandez ou confirmez : - La devise, et si les prix du menu incluent la TVA ou la taxe de vente (et le taux). - Le pourcentage de coût alimentaire cible (les fourchettes typiques sont dans `references/food-cost-basics.md` ; défaut 30). - Pour chaque ingrédient : prix d'achat, taille et unité de l'emballage, et rendement (partie utilisable après parage, épluchage, perte à la cuisson ou détérioration). - Pour chaque élément : quantités de la recette en quantités préparées, nombre de portions par lot, prix actuel du menu, emballage ou garniture par portion, et ventes hebdomadaires si connues. Si quelque chose manque, utilisez une hypothèse clairement étiquetée (par exemple "rendement de 90 pour cent supposé pour les avocats") et listez-la dans le rapport. ### 2. Construire la feuille de calcul Remplissez `templates/recipe-costing-sheet.md` en JSON. Utilisez des unités que le script connaît (g, kg, ml, l, oz, lb, each). Si un ingrédient est acheté à la pièce mais utilisé au poids, pesez une pièce et convertissez ; ne mélangez jamais les dimensions. ### 3. Exécuter le calculateur ```bash python3 scripts/cost_menu.py menu.json python3 scripts/cost_menu.py menu.json --target 28 python3 scripts/cost_menu.py menu.json --json ``` Le tableau montre le coût par portion, le prix du menu, le prix net sans taxe, le pourcentage de coût alimentaire, la marge de contribution (prix net moins coût), le prix au coût alimentaire cible (arrondi à la hausse), et la classe de menu engineering lorsque les ventes hebdomadaires sont données pour chaque élément. Les erreurs (ingrédients inconnus, incompatibilités d'unités) et les constatations HIGH font que le code de sortie est 1. Si vous ne pouvez pas exécuter le script, faites le même calcul à la main, ligne par ligne, et dites-le. ### 4. Recommander Utilisez `references/pricing-strategies.md` : 1. Corrigez d'abord les erreurs de données et relancez. 2. Pour les éléments HIGH et WARN, choisissez entre augmenter le prix, réduire la portion, changer un ingrédient coûteux, ou accepter un pourcentage plus élevé parce que la marge en argent est solide. Nommez le compromis. 3. Utilisez la classe de menu engineering pour décider où l'élément doit être placé sur le menu et s'il faut le promouvoir, le re-tarifer, le retravailler ou le retirer. 4. Relancez avec les changements proposés pour montrer l'avant et l'après. ### 5. Rapport Utilisez la mise en page du rapport dans `templates/recipe-costing-sheet.md`, comme dans `examples/example-cafe-menu.md`. ## Règles - Montrez la formule pour au moins un élément afin que le propriétaire puisse la vérifier : coût par portion / prix net x 100. - Ne traitez jamais le prix cible comme une instruction de baisser un prix existant ; c'est une référence. - Ne donnez pas de conseils fiscaux ou juridiques ; appliquez uniquement le taux de taxe fourni par l'utilisateur. - Respectez les allergènes et les allégations diététiques lors de la suggestion de substitutions, et ne suggérez jamais de baisser les normes de sécurité alimentaire ou de qualité. - Revérifiez les coûts lorsque les prix des fournisseurs changent de plus d'environ 5 pour cent. FILE:references/food-cost-basics.md # Bases du coût alimentaire ## Termes clés - **Coût tel qu'acheté (AP)** : ce que vous payez pour l'emballage, la caisse ou la pièce. - **Pourcentage de rendement** : la part utilisable après parage, épluchage, désossage, perte à la cuisson ou détérioration. Un filet de saumon paré de la peau et des arêtes peut avoir un rendement de 85 pour cent ; des avocats entiers où 1 sur 10 est inutilisable ont un rendement de 90 pour cent lorsqu'ils sont comptés à la pièce. - **Coût de la portion comestible (EP)** = coût AP par unité / (pourcentage de rendement / 100). Les recettes listent des quantités préparées et utilisables, elles sont donc calculées au coût EP. - **Coût de l'assiette (coût par portion)** = somme des coûts EP des ingrédients pour le lot / portions + extras par portion (emballage, serviette, garniture, coupelle de sauce). - **Prix net** = prix du menu / (1 + taux de taxe), lorsque les prix du menu incluent la TVA ou la taxe de vente. Le coût alimentaire doit être mesuré par rapport à l'argent que vous gardez, pas à la taxe que vous collectez. - **Pourcentage de coût alimentaire** = coût de l'assiette / prix net x 100. - **Marge de contribution** = prix net - coût de l'assiette. C'est l'argent que chaque vente laisse pour payer la main-d'œuvre, le loyer et le profit. ## Formule détaillée Filet de saumon acheté à 32,00 le kg avec un rendement de 85 pour cent : - Coût AP par g = 32,00 / 1000 = 0,032 - Coût EP par g = 0,032 / 0,85 = 0,0376 - Portion de 160 g = 160 x 0,0376 = 6,02 ## Cibles typiques de coût alimentaire (guide approximatif) | Concept | Pourcentage de coût alimentaire typique | | --- | --- | | Boissons café et espresso | 15 à 25 | | Produits de boulangerie | 20 à 30 | | Plats de brunch de café | 28 à 35 | | Plats principaux de restaurant décontracté | 28 à 35 | | Plats principaux steak et fruits de mer | 35 à 45 | | Pizza | 20 à 28 | | Plateaux de traiteur | 25 à 35 | Votre bonne cible dépend de la main-d'œuvre, du loyer et du volume. Un élément à faible main-d'œuvre peut avoir un pourcentage de coût alimentaire plus élevé et être très rentable. ## Erreurs de calcul courantes 1. Oublier les petits éléments : huile, beurre pour la poêle, sel, garniture, sauces et emballages à emporter. Ajoutez-les ou utilisez extras_per_portion. 2. Utiliser le coût AP sans rendement pour les protéines et les produits frais. 3. Mesurer le coût alimentaire par rapport aux prix qui incluent la taxe. 4. Calculer le coût de la fiche de recette au lieu de ce que la cuisine sert réellement (dérive des portions). Pesez cinq portions réelles. 5. Prix de fournisseurs obsolètes. Mettez à jour la feuille lorsqu'un prix change d'environ 5 pour cent ou plus. 6. Mélanger les unités : un ingrédient acheté à la pièce mais utilisé au poids doit être pesé une fois. 7. Ignorer le gaspillage et les repas du personnel ; suivez-les séparément et comparez le coût alimentaire réel (à partir de l'inventaire) avec ce coût théorique. ## Coût théorique par rapport au coût réel Cette compétence calcule le coût théorique : ce que la nourriture devrait coûter si les recettes sont suivies. Coût alimentaire réel = (inventaire d'ouverture + achats - inventaire de clôture) / ventes alimentaires nettes. Un écart de plus d'environ 2 à 3 points signifie généralement du gaspillage, une dérive des portions, du vol ou des prix incorrects sur la feuille. FILE:references/pricing-strategies.md # Stratégies de tarification et menu engineering ## Façons de fixer un prix 1. **Pourcentage de coût alimentaire cible** : prix = coût de l'assiette / cible x (1 + taux de taxe), arrondi à la hausse. Simple, et c'est la colonne "AT TARGET" du script. Point faible : les articles bon marché finissent sous-évalués et les protéines chères surévaluées. 2. **Marge de contribution** : décidez de l'argent que chaque élément doit gagner (par exemple au moins 5,00 pour un plat principal), puis prix = (coût de l'assiette + marge) x (1 + taux de taxe). Meilleur pour les protéines à coût élevé. 3. **Vérification du marché** : comparez avec trois à cinq endroits similaires à proximité. La perception du prix compte autant que le coût. 4. **Mélange** : partez du prix cible, vérifiez la marge en argent, puis vérifiez la cohérence avec le marché. ## Arrondi et présentation - Arrondissez à la hausse au pas utilisé par votre menu (0,10, 0,50 ou nombres entiers). Les menus haut de gamme utilisent souvent des nombres entiers sans signes de devise ; les menus décontractés finissent souvent par .50 ou .90. - Évitez de nombreuses petites augmentations sur tout le menu à la fois ; augmentez d'abord les éléments avec la marge la plus faible. - Gardez les écarts de prix logiques : une option de lait d'avoine doit couvrir son coût supplémentaire (la boisson d'avoine coûte souvent environ deux fois plus que le lait de vache par litre). ## Menu engineering Nécessite les ventes hebdomadaires pour chaque élément. Le script utilise : - **Ligne de popularité** : un élément est populaire s'il se vend au moins 70 pour cent d'une part égale (avec 5 éléments, 0,7 x 20 pour cent = 14 pour cent des unités vendues). - **Ligne de marge** : la marge de contribution moyenne pondérée par les ventes. | Classe | Popularité | Marge | Que faire | | --- | --- | --- | --- | | Star | élevée | élevée | Gardez la qualité et la portion constantes, placez-le au meilleur endroit du menu, les petites augmentations de prix sont généralement sûres. | | Plowhorse | élevée | faible | Augmentez un peu le prix, réduisez le coût (portion, garniture, fournisseur), ou associez-le à un ajout à forte marge. Ne le retirez pas. | | Puzzle | faible | élevée | Promouvez-le : meilleur placement au menu, une description, une recommandation du personnel, une photo. Vérifiez que le prix n'effraie pas les clients. | | Dog | faible | faible | Retravaillez la recette ou le prix, ou retirez-le, sauf s'il sert un objectif (menu enfants, option diététique, élément signature). | ## Choisir une solution pour un élément à coût alimentaire élevé | Option | Bonne quand | Risque | | --- | --- | --- | | Augmenter le prix | l'élément est populaire et le marché le permet | moins de ventes si le saut est important | | Réduire la portion | les portions sont plus grandes que ce que les clients attendent | les clients le remarquent ; gardez la perception de valeur | | Changer un ingrédient | une option moins chère de qualité égale existe | changements d'allergènes et de goût ; mettez à jour le texte du menu | | Accepter un pourcentage plus élevé | la marge en argent est la plus élevée du menu | nécessite du volume pour être rentable | | Retirer l'élément | c'est un Dog sans rôle stratégique | les habitués peuvent le manquer | Relancez toujours le calculateur avec le changement proposé et montrez l'avant et l'après. FILE:templates/recipe-costing-sheet.md # Feuille de calcul du coût des recettes (entrée pour scripts/cost_menu.py) Enregistrez sous `menu.json`. Les quantités dans les recettes sont des quantités préparées (utilisables). ```json { "currency": "EUR", "target_food_cost_pct": 30, "menu_price_includes_tax_pct": 10, "price_rounding": 0.10, "ingredients": [ {"name": "flour", "price": 0.95, "per": "1 kg"}, {"name": "butter", "price": 9.80, "per": "1 kg"}, {"name": "eggs", "price": 3.60, "per": "12 each"}, {"name": "blueberries", "price": 16.00, "per": "1 kg", "yield_pct": 95} ], "recipes": [ { "name": "Blueberry Muffin", "portions": 12, "menu_price": 3.20, "sold_per_week": 90, "extras_per_portion": 0.06, "items": [["flour", "500 g"], ["butter", "180 g"], ["eggs", "3 each"], ["blueberries", "300 g"]] } ] } ``` Notes sur les champs : - `per` : l'emballage que vous achetez, comme "<montant> <unité>" (g, kg, mg, ml, cl, dl, l, oz, lb, each). - `yield_pct` : 1 à 100, défaut 100. - `menu_price_includes_tax_pct` : 0 si les prix du menu sont affichés sans taxe. - `sold_per_week` : donnez-le pour chaque élément (ou aucun) pour obtenir les classes de menu engineering. - `extras_per_portion` : emballage, serviettes, garniture, coupelles de sauce, en argent. Exécutez : `python3 scripts/cost_menu.py menu.json [--target 30] [--json]` --- # Rapport de calcul du coût du menu : <entreprise> - <date> **Coût alimentaire cible :** <x>% **Les prix incluent la taxe :** <taux ou non> **Devise :** <code> **Hypothèses :** <rendements, prix manquants, poids des portions> ## Résultats (avant) | Élément | Coût/portion | Prix | Net | % Alim. | Marge | À la cible | Classe | | --- | --- | --- | --- | --- | --- | --- | --- | ## Vérification de la formule <un élément détaillé ligne par ligne> ## Ce qui nécessite une attention 1. **<élément>** - <constatation>. Options : <prix / portion / ingrédient / accepter>. Recommandation : <une>. ## Changements proposés et résultats (après) <changements, puis le nouveau tableau ou les lignes modifiées> ## Actions de menu engineering - Stars : <éléments et action> - Plowhorses : <éléments et action> - Puzzles : <éléments et action> - Dogs : <éléments et action> ## Prochaines étapes - <pesez les portions réelles, mettez à jour les prix des fournisseurs, suivez le coût alimentaire réel mensuellement> FILE:examples/example-cafe-menu.md # Exemple : un menu de café à cinq éléments **Utilisateur :** "Nous sommes un petit café de brunch. Les prix incluent 10 pour cent de TVA et je veux environ 30 pour cent de coût alimentaire. Voici mes prix de fournisseurs et mes recettes. Pourquoi ma marge est-elle si mince ?" La feuille contient 16 ingrédients et 5 éléments avec les ventes hebdomadaires (rendement des avocats de 90 pour cent car environ 1 sur 10 est inutilisable ; saumon 85 pour cent après parage). **Commande :** ```bash python3 scripts/cost_menu.py cafe-menu.json ``` **Sortie (avant) :** ``` ÉLÉMENT COÛT PRIX NET % ALIM. MARGE À LA CIBLE CLASSE Avocado Toast 3.13 9.50 8.64 36.2 5.51 11.50 Star Salmon Spinach Bowl 8.02 14.50 13.18 60.8 5.16 29.50 Puzzle Flat White 0.72 3.80 3.45 21.0 2.73 2.70 Plowhorse Oat Flat White 0.91 4.20 3.82 23.9 2.91 3.40 Plowhorse Blueberry Muffin 0.79 3.20 2.91 27.2 2.12 3.00 Dog Constatations (8) : [HIGH] Salmon Spinach Bowl : coût alimentaire 60,8% bien au-dessus de la cible de 30% ; prix EUR 29,50 ou réduire le coût de 4,06 par portion [WARN] Avocado Toast : coût alimentaire 36,2% au-dessus de la cible de 30% ; prix à la cible serait EUR 11,50 [INFO] Salmon Spinach Bowl : le filet de saumon représente 76% du coût ; son prix ou sa portion importe le plus [INFO] menu engineering : marge moyenne pondérée EUR 3,22, ligne de popularité 14,0% des éléments vendus [INFO] ingrédient 'truffle oil' n'est utilisé dans aucune recette ``` --- # Rapport de calcul du coût du menu : café de brunch - octobre **Coût alimentaire cible :** 30% **Les prix incluent la taxe :** 10% TVA **Devise :** EUR **Hypothèses :** rendement des avocats 90%, saumon 85%, épinards 90% ; extras 0,10 par plat, 0,12 par café (tasse et couvercle), 0,06 par muffin. ## Vérification de la formule (Salmon Spinach Bowl, avant) - Saumon 160 g x (32,00 / 1000 / 0,85) = 6,02 - Épinards 70 g x (14,00 / 1000 / 0,90) = 1,09 ; œuf 0,30 ; tomates 0,36 ; huile d'olive 0,15 ; extras 0,10 - Coût par portion = 8,02 ; prix net = 14,50 / 1,10 = 13,18 ; coût alimentaire = 8,02 / 13,18 x 100 = 60,8% ## Ce qui nécessite une attention 1. **Salmon Spinach Bowl (HIGH, Puzzle)** - 60,8% de coût alimentaire ; le saumon représente 76% du coût. Le fixer au prix cible (29,50) est irréaliste pour un café. Recommandation : réduire le saumon à 120 g (toujours une portion généreuse pour un bol) et augmenter le prix à 17,50 ; accepter environ 40% de coût alimentaire car la marge devient la plus élevée du menu. 2. **Avocado Toast (WARN, Star)** - 36,2%. C'est le plat le plus vendu, donc une augmentation de 1,00 à 10,50 est à faible risque. 3. **Flat White et Oat Flat White (Plowhorses)** - pourcentages sains (21 à 24%) mais petites marges ; ne remisez pas. Gardez le supplément d'avoine à 0,40 : la boisson d'avoine coûte 0,19 de plus par tasse que le lait. 4. **Blueberry Muffin (Dog)** - pourcentage correct, faible marge et faibles ventes. Essayez un lot avec du café avant de le retirer. 5. **Truffle oil** est sur la feuille mais dans aucune recette : retirez-le des commandes ou de la feuille. ## Changements proposés et résultats (après) Avocado Toast 10,50 ; Salmon Spinach Bowl 120 g de saumon à 17,50. Relancez : `python3 scripts/cost_menu.py cafe-menu-revised.json` ``` ÉLÉMENT COÛT PRIX NET % ALIM. MARGE À LA CIBLE CLASSE Avocado Toast 3.13 10.50 9.55 32.8 6.42 11.50 Star Salmon Spinach Bowl 6.51 17.50 15.91 40.9 9.40 23.90 Puzzle Flat White 0.72 3.80 3.45 21.0 2.73 2.70 Plowhorse Oat Flat White 0.91 4.20 3.82 23.9 2.91 3.40 Plowhorse Blueberry Muffin 0.79 3.20 2.91 27.2 2.12 3.00 Dog Constatations (6) : [WARN] Salmon Spinach Bowl : coût alimentaire 40,9% au-dessus de la cible de 30% ; prix à la cible serait EUR 23,90 [INFO] menu engineering : marge moyenne pondérée EUR 3,56, ligne de popularité 14,0% des éléments vendus ``` Code de sortie 0. Le WARN restant est accepté volontairement : 9,40 de marge par bol contre 5,16 avant. ## Actions de menu engineering - Stars : Avocado Toast - gardez la recette constante, en haut de la section brunch. - Plowhorses : Flat White, Oat Flat White - pas de remises ; suggérez une pâtisserie avec chaque café. - Puzzles : Salmon Spinach Bowl - donnez-lui une courte description et une recommandation du personnel ; vérifiez les ventes après 4 semaines au nouveau prix. - Dogs : Blueberry Muffin - testez un lot café + muffin pendant 4 semaines, puis décidez. ## Prochaines étapes - Pesez cinq portions réelles de saumon cette semaine pour confirmer que la spécification de 120 g est suivie. - Mettez à jour les prix des fournisseurs mensuellement et relancez la feuille. - Comparez avec le coût alimentaire réel de l'inventaire à la fin du mois. FILE:scripts/cost_menu.py #!/usr/bin/env python3 """Calcule le coût des éléments de menu à partir des recettes et des prix d'achat, et suggère des prix de menu. Utilisation : python3 cost_menu.py menu.json [--target 30] [--json] cat menu.json | python3 cost_menu.py - JSON d'entrée (voir templates/recipe-costing-sheet.md) : { "currency": "EUR", "target_food_cost_pct": 30, # optionnel, défaut 30 (ou --target) "menu_price_includes_tax_pct": 10, # optionnel ; TVA/taxe de vente incluse dans les prix du menu "price_rounding": 0.10, # optionnel ; les prix suggérés arrondissent À LA HAUSSE à ce pas "ingredients": [ {"name": "butter", "price": 9.80, "per": "1 kg", "yield_pct": 100} ], "recipes": [ {"name": "Croissant", "portions": 12, "menu_price": 3.20, "sold_per_week": 180, "extras_per_portion": 0.05, # optionnel : emballage, serviette, garniture "items": [["butter", "600 g"], ["flour", "1 kg"]]} ] } Unités : g, kg, mg, ml, cl, dl, l, oz, lb, each (aussi pc, pcs, piece, unit, egg). Les quantités des recettes sont les montants préparés (utilisables). yield_pct est la part utilisable de ce que vous achetez après parage, épluchage, perte à la cuisson ou détérioration. Par recette : coût par portion, pourcentage de coût alimentaire du prix net (hors taxes) du menu, marge de contribution, prix suggéré à la cible, et les trois plus grands facteurs de coût. Avec sold_per_week sur chaque recette, ajoute une classe de menu engineering (Star, Plowhorse, Puzzle, Dog). Code de sortie : 0 ok, 1 erreurs dans les données ou constatations HIGH, 2 erreur d'utilisation ou d'entrée. Bibliothèque standard uniquement. """ import json import math import re import sys UNITS = { # unité -> (dimension, facteur vers l'unité de base g / ml / each) "mg": ("mass", 0.001), "g": ("mass", 1.0), "kg": ("mass", 1000.0), "oz": ("mass", 28.3495), "lb": ("mass", 453.592), "ml": ("volume", 1.0), "cl": ("volume", 10.0), "dl": ("volume", 100.0), "l": ("volume", 1000.0), "each": ("count", 1.0), "pc": ("count", 1.0), "pcs": ("count", 1.0), "piece": ("count", 1.0), "pieces": ("count", 1.0), "unit": ("count", 1.0), "units": ("count", 1.0), "egg": ("count", 1.0), "eggs": ("count", 1.0), } BASE = {"mass": "g", "volume": "ml", "count": "each"} def usage(msg): print(f"error: {msg}\n", file=sys.stderr) print(__doc__.strip().split("\n\n")[1], file=sys.stderr) sys.exit(2) def parse_qty(text): """'600 g' -> (600.0, 'mass', 600.0 en unités de base).""" m = re.fullmatch(r"\s*(\d+(?:[.,]\d+)?)\s*([a-zA-Z]+)?\s*", str(text)) if not m: raise ValueError(f"impossible de lire la quantité {text!r}") qty = float(m.group(1).replace(",", ".")) unit = (m.group(2) or "each").lower() if unit not in UNITS: raise ValueError(f"unité inconnue {unit!r} dans {text!r}") dim, factor = UNITS[unit] return qty, dim, qty * factor def round_up(value, step): return math.ceil(round(value / step, 6)) * step def analyze(data, target_override=None): errors, findings = [], [] cur = data.get("currency", "") target = float(target_override or data.get("target_food_cost_pct", 30)) tax = float(data.get("menu_price_includes_tax_pct", 0)) step = float(data.get("price_rounding", 0.10)) ingredients = {} for ing in data.get("ingredients", []): name = str(ing.get("name", "")).strip().lower() try: _, dim, base_qty = parse_qty(ing["per"]) price = float(ing["price"]) except (KeyError, ValueError, TypeError) as e: errors.append(f"ingrédient {name or '?'} : {e}") continue y = float(ing.get("yield_pct", 100)) if not 0 < y <= 100: errors.append(f"ingrédient {name} : yield_pct doit être entre 1 et 100") continue ingredients[name] = {"dim": dim, "cost_per_base": price / base_qty / (y / 100), "yield": y, "used": False} results = [] for rec in data.get("recipes", []): rname = rec.get("name", "?") portions = float(rec.get("portions", 1) or 1) lines, bad = [], False for item in rec.get("items", []): iname, qtext = str(item[0]).strip().lower(), item[1] ing = ingredients.get(iname) if not ing: errors.append(f"{rname} : ingrédient inconnu {iname!r} (ajoutez-le aux ingrédients)") bad = True continue ing["used"] = True try: _, dim, base_qty = parse_qty(qtext) except ValueError as e: errors.append(f"{rname} : {e}") bad = True continue if dim != ing["dim"]: errors.append(f"{rname} : {iname} est acheté par {BASE[ing['dim']]} mais utilisé par {BASE[dim]} ({qtext}) ; " f"convertissez-le (par exemple pesez une pièce)") bad = True continue lines.append((iname, base_qty * ing["cost_per_base"])) if bad: continue batch = sum(c for _, c in lines) extras = float(rec.get("extras_per_portion", 0)) cost = batch / portions + extras price = float(rec.get("menu_price", 0)) net = price / (1 + tax / 100) if price else 0.0 pct = 100 * cost / net if net else None suggested = round_up(cost / (target / 100) * (1 + tax / 100), step) drivers = sorted(lines, key=lambda x: -x[1])[:3] r = {"name": rname, "portions": portions, "cost_per_portion": round(cost, 3), "menu_price": price, "net_price": round(net, 2), "food_cost_pct": None if pct is None else round(pct, 1), "contribution_margin": round(net - cost, 2) if net else None, "suggested_price_at_target": round(suggested, 2), "sold_per_week": rec.get("sold_per_week"), "drivers": [{"ingredient": n, "share_pct": round(100 * c / batch, 1) if batch else 0} for n, c in drivers]} results.append(r) if pct is None: findings.append(("WARN", rname, f"pas de menu_price ; suggéré {cur} {suggested:.2f} à {target:g}% de coût alimentaire")) elif pct > target + 15: findings.append(("HIGH", rname, f"coût alimentaire {pct:.1f}% bien au-dessus de la cible de {target:g}% ; " f"prix {cur} {suggested:.2f} ou réduire le coût de {cost - net * target / 100:.2f} par portion")) elif pct > target + 5: findings.append(("WARN", rname, f"coût alimentaire {pct:.1f}% au-dessus de la cible de {target:g}% ; " f"prix à la cible serait {cur} {suggested:.2f}")) elif pct < target - 15: findings.append(("INFO", rname, f"coût alimentaire seulement {pct:.1f}% ; vérifiez que la recette liste chaque ingrédient et la taille des portions")) if drivers and batch and drivers[0][1] / batch > 0.5: findings.append(("INFO", rname, f"{drivers[0][0]} représente {100 * drivers[0][1] / batch:.0f}% du coût ; " f"son prix ou sa portion importe le plus")) sold = [r for r in results if isinstance(r["sold_per_week"], (int, float)) and r["contribution_margin"] is not None] if sold and len(sold) == len(results) and len(sold) >= 3: total = sum(r["sold_per_week"] for r in sold) pop_line = 0.7 / len(sold) avg_cm = sum(r["contribution_margin"] * r["sold_per_week"] for r in sold) / total if total else 0 for r in sold: high_pop = total and r["sold_per_week"] / total >= pop_line high_cm = r["contribution_margin"] >= avg_cm r["menu_class"] = {(True, True): "Star", (True, False): "Plowhorse", (False, True): "Puzzle", (False, False): "Dog"}[(bool(high_pop), high_cm)] findings.append(("INFO", None, f"menu engineering : marge moyenne pondérée {cur} {avg_cm:.2f}, " f"ligne de popularité {100 * pop_line:.1f}% des éléments vendus")) for name, ing in ingredients.items(): if not ing["used"]: findings.append(("INFO", None, f"ingrédient {name!r} n'est utilisé dans aucune recette")) return {"currency": cur, "target_pct": target, "tax_pct": tax, "recipes": results, "errors": errors, "findings": [{"severity": s, "recipe": n, "message": m} for s, n, m in findings]} def main(argv): target, as_json, paths = None, False, [] it = iter(argv) for a in it: if a == "--target": try: target = float(next(it, "")) except ValueError: usage("--target nécessite un nombre, par exemple 30") if not 5 <= target <= 80: usage("--target doit être un pourcentage de coût alimentaire entre 5 et 80") elif a == "--json": as_json = True elif a.startswith("--"): usage(f"option inconnue {a}") else: paths.append(a) if len(paths) != 1: usage("donnez exactement un fichier JSON de menu, ou - pour l'entrée standard") try: raw = sys.stdin.read() if paths[0] == "-" else open(paths[0], encoding="utf-8").read() data = json.loads(raw) except (OSError, ValueError) as e: print(f"error : impossible de lire le JSON du menu : {e}", file=sys.stderr) return 2 if not data.get("recipes"): print("error : pas de recettes dans l'entrée", file=sys.stderr) return 2 rep = analyze(data, target) if as_json: print(json.dumps(rep, indent=2)) else: cur = rep["currency"] print(f"Coût alimentaire cible {rep['target_pct']:g}% | les prix incluent {rep['tax_pct']:g}% de taxe | devise {cur}\n") print(f"{'ÉLÉMENT':<22} {'COÛT':>7} {'PRIX':>7} {'NET':>7} {'% ALIM.':>6} {'MARGE':>7} {'À LA CIBLE':>9} CLASSE") for r in rep["recipes"]: pct = "-" if r["food_cost_pct"] is None else f"{r['food_cost_pct']:.1f}" cm = "-" if r["contribution_margin"] is None else f"{r['contribution_margin']:.2f}" print(f"{r['name'][:22]:<22} {r['cost_per_portion']:>7.2f} {r['menu_price']:>7.2f} {r['net_price']:>7.2f} " f"{pct:>6} {cm:>7} {r['suggested_price_at_target']:>9.2f} {r.get('menu_class', '-')}") print("\nPrincipaux facteurs de coût :") for r in rep["recipes"]: print(f" {r['name']} : " + ", ".join(f"{d['ingredient']} {d['share_pct']:g}%" for d in r["drivers"])) if rep["errors"]: print(f"\nErreurs ({len(rep['errors'])}):") for e in rep["errors"]: print(f" [ERROR] {e}") print(f"\nConstatations ({len(rep['findings'])}):") order = {"HIGH": 0, "WARN": 1, "INFO": 2} for f in sorted(rep["findings"], key=lambda f: order[f["severity"]]): print(f" [{f['severity']}] {f['recipe'] + ': ' if f['recipe'] else ''}{f['message']}") bad = rep["errors"] or any(f["severity"] == "HIGH" for f in rep["findings"]) return 1 if bad else 0 if __name__ == "__main__": sys.exit(main(sys.argv[1:]))

Connectez-vous pour voir le prompt complet

Continuer avec:

En vous connectant, vous acceptez nos Conditions et Confidentialité

Utilisation

Ce prompt est conçu pour être utilisé avec business. Copiez le contenu ci-dessus et collez-le dans votre outil d’IA préféré.

Pour de meilleurs résultats, personnalisez les espaces réservés (indiqués par des crochets ou des majuscules) selon vos besoins.

Références

Catégories :business| prompts.chat| food-cost| menu-pricing

Discussion