summaryrefslogtreecommitdiff
path: root/kitchen/management/commands/seed.py
blob: 4aa74bf024cc83c61844482e241e7cd294369f2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
"""
Seed the database with initial data:
- Tags
- Ingredients (from current pantry + recipe knowledge)
- Current pantry items (migrated from Food/Pantry.md)
- Meta-recipes: Stir Fry and Traybake
"""

from datetime import date
from decimal import Decimal

from django.core.management.base import BaseCommand

from kitchen.models import (
    Tag,
    Ingredient,
    PantryItem,
    MetaRecipe,
    Slot,
    SlotOption,
    MetaRecipeBase,
)


class Command(BaseCommand):
    help = "Seed database with initial ingredients, pantry, and meta-recipes"

    def handle(self, *args, **options):
        self.stdout.write("Creating tags...")
        tags = {}
        for name in ["protein", "carb", "veg", "seasoning", "dairy", "sauce", "staple", "frozen"]:
            tags[name], _ = Tag.objects.get_or_create(name=name)

        self.stdout.write("Creating ingredients...")
        ingredients = {}

        def make_ingredient(name, unit, tag_names, shelf_life=None, aliases=None):
            obj, _ = Ingredient.objects.get_or_create(
                name=name,
                defaults={
                    "default_unit": unit,
                    "shelf_life_days": shelf_life,
                    "aliases": aliases or [],
                },
            )
            for t in tag_names:
                obj.tags.add(tags[t])
            ingredients[name] = obj
            return obj

        # Proteins
        make_ingredient("chicken mini fillets", "items", ["protein"], shelf_life=2, aliases=["chicken fillets", "mini fillets"])
        make_ingredient("chicken thighs", "items", ["protein"], shelf_life=2, aliases=["chicken thigh"])
        make_ingredient("pork mince", "g", ["protein"], shelf_life=2, aliases=["pork mince 500g"])
        make_ingredient("sausages", "items", ["protein"], shelf_life=5, aliases=["pork sausages"])

        # Carbs
        make_ingredient("egg noodles", "nests", ["carb"], aliases=["noodles", "egg noodle nests"])
        make_ingredient("microwave rice", "packets", ["carb"], aliases=["rice"])
        make_ingredient("pasta", "g", ["carb"], aliases=["dried pasta"])
        make_ingredient("bread", "loaves", ["carb"], shelf_life=5)
        make_ingredient("frozen chips", "bags", ["carb", "frozen", "staple"], aliases=["chips", "McCain chips"])

        # Veg
        make_ingredient("onions", "items", ["veg", "staple"], aliases=["onion"])
        make_ingredient("garlic", "bulbs", ["veg"], shelf_life=14, aliases=["garlic bulb"])
        make_ingredient("frozen stir fry veg", "bags", ["veg", "frozen"], aliases=["stir fry veg", "Birds Eye stir fry veg"])
        make_ingredient("broccoli", "heads", ["veg"], shelf_life=5)
        make_ingredient("peppers", "items", ["veg"], shelf_life=7, aliases=["pepper", "bell pepper"])
        make_ingredient("potatoes", "items", ["veg"], shelf_life=14, aliases=["Cyprus potatoes"])
        make_ingredient("chopped tomatoes", "tins", ["veg"], aliases=["tinned tomatoes"])

        # Dairy / Other
        make_ingredient("eggs", "items", ["protein"], shelf_life=14, aliases=["free range eggs"])
        make_ingredient("milk", "bottles", ["dairy"], shelf_life=7)
        make_ingredient("Lurpak spreadable", "tubs", ["dairy"], aliases=["butter", "Lurpak"])

        # Seasonings & Sauces
        make_ingredient("salt", "n/a", ["seasoning", "staple"])
        make_ingredient("black pepper", "n/a", ["seasoning", "staple"])
        make_ingredient("olive oil", "bottles", ["seasoning", "staple"])
        make_ingredient("paprika", "n/a", ["seasoning", "staple"])
        make_ingredient("garlic powder", "n/a", ["seasoning", "staple"])
        make_ingredient("soy sauce", "bottles", ["sauce"], aliases=["soy"])
        make_ingredient("Lao Gan Ma", "jars", ["sauce"], aliases=["chilli crisp"])
        make_ingredient("peanut butter", "jars", ["staple"], aliases=["Whole Earth crunchy"])

        # Other
        make_ingredient("baked beans", "tins", ["staple"])
        make_ingredient("freezer bags", "boxes", ["staple"], aliases=["Tesco tie handle"])

        self.stdout.write(f"  Created {len(ingredients)} ingredients")

        # --- Pantry Items (from current Pantry.md as of 31 Mar 2026) ---
        self.stdout.write("Creating pantry items...")

        def add_pantry(name, qty, unit, location, expiry=None, is_staple=False, notes=""):
            PantryItem.objects.get_or_create(
                ingredient=ingredients[name],
                defaults={
                    "quantity": Decimal(str(qty)),
                    "unit": unit,
                    "location": location,
                    "expiry_date": expiry,
                    "is_staple": is_staple,
                    "notes": notes,
                },
            )

        # Fridge
        add_pantry("onions", 2, "items", "fridge", is_staple=True)
        add_pantry("milk", 1, "bottles", "fridge", expiry=date(2026, 4, 3))
        add_pantry("egg noodles", 1, "nests", "fridge")
        add_pantry("garlic", 1, "bulbs", "fridge", expiry=date(2026, 4, 2), notes="minus 2 cloves")
        add_pantry("bread", 1, "loaves", "fridge", expiry=date(2026, 4, 1))
        add_pantry("pasta", 4, "portions", "cupboard")
        add_pantry("microwave rice", 2, "packets", "cupboard")
        add_pantry("peanut butter", 1, "jars", "cupboard")
        add_pantry("Lurpak spreadable", 1, "tubs", "fridge")
        add_pantry("Lao Gan Ma", 1, "jars", "cupboard")
        add_pantry("sausages", 3, "items", "fridge", expiry=date(2026, 3, 30), notes="Likely expired — sniff test")

        # Freezer
        add_pantry("sausages", 3, "items", "freezer", notes="From frozen pack")
        add_pantry("frozen chips", 1, "bags", "freezer", is_staple=True)
        add_pantry("bread", 1, "loaves", "freezer", notes="Sliced")

        # Staples (seasonings — always in cupboard)
        for name in ["salt", "black pepper", "olive oil", "paprika", "garlic powder"]:
            add_pantry(name, 1, "n/a", "cupboard", is_staple=True)

        # Out of stock (for reference)
        add_pantry("eggs", 0, "items", "fridge", notes="OUT — restock")
        add_pantry("baked beans", 1, "tins", "cupboard")
        add_pantry("freezer bags", 1, "boxes", "cupboard")

        self.stdout.write("  Pantry seeded")

        # --- Meta-Recipes ---
        self.stdout.write("Creating meta-recipes...")

        # === STIR FRY ===
        stir_fry, _ = MetaRecipe.objects.get_or_create(
            name="Stir Fry",
            defaults={
                "method": (
                    "1. Defrost protein if frozen (cold water, ~30 mins for fillets)\n"
                    "2. Slice protein thin, fry in oil til cooked through\n"
                    "3. Dice onion + mince garlic, add to pan\n"
                    "4. Add veg (frozen goes straight in)\n"
                    "5. Boil carb separately if needed (noodles 4 mins, rice per packet)\n"
                    "6. Toss everything together with sauce\n"
                    "7. Optional: push to one side, crack egg in, scramble, mix through"
                ),
                "prep_time_mins": 10,
                "cook_time_mins": 15,
                "default_servings": 2,
                "gear_needed": "frying pan, saucepan",
                "tags": ["quick", "one-pan"],
            },
        )

        # Stir fry slots
        sf_protein, _ = Slot.objects.get_or_create(
            meta_recipe=stir_fry, name="protein", defaults={"required": True, "max_choices": 1}
        )
        sf_carb, _ = Slot.objects.get_or_create(
            meta_recipe=stir_fry, name="carb", defaults={"required": True, "max_choices": 1}
        )
        sf_veg, _ = Slot.objects.get_or_create(
            meta_recipe=stir_fry, name="veg", defaults={"required": True, "max_choices": 3}
        )
        sf_sauce, _ = Slot.objects.get_or_create(
            meta_recipe=stir_fry, name="sauce", defaults={"required": False, "max_choices": 2}
        )

        # Stir fry slot options
        SlotOption.objects.get_or_create(slot=sf_protein, ingredient=ingredients["chicken mini fillets"], defaults={"quantity_per_serving": Decimal("2"), "unit": "items", "notes": "defrost first"})
        SlotOption.objects.get_or_create(slot=sf_protein, ingredient=ingredients["pork mince"], defaults={"quantity_per_serving": Decimal("250"), "unit": "g"})
        SlotOption.objects.get_or_create(slot=sf_carb, ingredient=ingredients["egg noodles"], defaults={"quantity_per_serving": Decimal("2"), "unit": "nests"})
        SlotOption.objects.get_or_create(slot=sf_carb, ingredient=ingredients["microwave rice"], defaults={"quantity_per_serving": Decimal("1"), "unit": "packets"})
        SlotOption.objects.get_or_create(slot=sf_veg, ingredient=ingredients["frozen stir fry veg"], defaults={"quantity_per_serving": Decimal("0.5"), "unit": "bags"})
        SlotOption.objects.get_or_create(slot=sf_veg, ingredient=ingredients["broccoli"], defaults={"quantity_per_serving": Decimal("0.5"), "unit": "heads"})
        SlotOption.objects.get_or_create(slot=sf_veg, ingredient=ingredients["peppers"], defaults={"quantity_per_serving": Decimal("1"), "unit": "items"})
        SlotOption.objects.get_or_create(slot=sf_sauce, ingredient=ingredients["soy sauce"], defaults={"quantity_per_serving": Decimal("1"), "unit": "splash"})
        SlotOption.objects.get_or_create(slot=sf_sauce, ingredient=ingredients["Lao Gan Ma"], defaults={"quantity_per_serving": Decimal("1"), "unit": "spoonful"})

        # Stir fry base ingredients
        MetaRecipeBase.objects.get_or_create(meta_recipe=stir_fry, ingredient=ingredients["onions"], defaults={"quantity_per_serving": Decimal("1"), "unit": "items"})
        MetaRecipeBase.objects.get_or_create(meta_recipe=stir_fry, ingredient=ingredients["garlic"], defaults={"quantity_per_serving": Decimal("2"), "unit": "cloves"})
        MetaRecipeBase.objects.get_or_create(meta_recipe=stir_fry, ingredient=ingredients["olive oil"], defaults={"quantity_per_serving": Decimal("1"), "unit": "splash"})

        # === TRAYBAKE ===
        traybake, _ = MetaRecipe.objects.get_or_create(
            name="Traybake",
            defaults={
                "method": (
                    "1. Preheat oven to 200°C\n"
                    "2. Dice onion, chop veg into chunks\n"
                    "3. Toss protein + veg in oil and seasoning on baking tray\n"
                    "4. Spread out in single layer\n"
                    "5. Oven for 30-40 mins, turning halfway\n"
                    "6. If using chicken thighs: remove skin before cooking"
                ),
                "prep_time_mins": 10,
                "cook_time_mins": 35,
                "default_servings": 2,
                "gear_needed": "baking tray",
                "tags": ["easy", "one-tray", "batch-cook"],
            },
        )

        # Traybake slots
        tb_protein, _ = Slot.objects.get_or_create(
            meta_recipe=traybake, name="protein", defaults={"required": True, "max_choices": 1}
        )
        tb_veg, _ = Slot.objects.get_or_create(
            meta_recipe=traybake, name="veg", defaults={"required": True, "max_choices": 3}
        )
        tb_seasoning, _ = Slot.objects.get_or_create(
            meta_recipe=traybake, name="seasoning", defaults={"required": True, "max_choices": 1}
        )

        # Traybake slot options
        SlotOption.objects.get_or_create(slot=tb_protein, ingredient=ingredients["sausages"], defaults={"quantity_per_serving": Decimal("3"), "unit": "items"})
        SlotOption.objects.get_or_create(slot=tb_protein, ingredient=ingredients["chicken thighs"], defaults={"quantity_per_serving": Decimal("2"), "unit": "items", "notes": "skin off"})
        SlotOption.objects.get_or_create(slot=tb_veg, ingredient=ingredients["peppers"], defaults={"quantity_per_serving": Decimal("1"), "unit": "items"})
        SlotOption.objects.get_or_create(slot=tb_veg, ingredient=ingredients["broccoli"], defaults={"quantity_per_serving": Decimal("0.5"), "unit": "heads"})
        SlotOption.objects.get_or_create(slot=tb_veg, ingredient=ingredients["potatoes"], defaults={"quantity_per_serving": Decimal("2"), "unit": "items"})
        SlotOption.objects.get_or_create(slot=tb_veg, ingredient=ingredients["frozen chips"], defaults={"quantity_per_serving": Decimal("1"), "unit": "handful"})
        SlotOption.objects.get_or_create(slot=tb_seasoning, ingredient=ingredients["paprika"], defaults={"quantity_per_serving": Decimal("1"), "unit": "tsp"})

        # Traybake base ingredients
        MetaRecipeBase.objects.get_or_create(meta_recipe=traybake, ingredient=ingredients["onions"], defaults={"quantity_per_serving": Decimal("1"), "unit": "items"})
        MetaRecipeBase.objects.get_or_create(meta_recipe=traybake, ingredient=ingredients["olive oil"], defaults={"quantity_per_serving": Decimal("1"), "unit": "drizzle"})
        MetaRecipeBase.objects.get_or_create(meta_recipe=traybake, ingredient=ingredients["salt"], defaults={"quantity_per_serving": Decimal("1"), "unit": "pinch"})
        MetaRecipeBase.objects.get_or_create(meta_recipe=traybake, ingredient=ingredients["black pepper"], defaults={"quantity_per_serving": Decimal("1"), "unit": "pinch"})

        self.stdout.write(self.style.SUCCESS("✅ Seed complete!"))
        self.stdout.write(f"  Tags: {Tag.objects.count()}")
        self.stdout.write(f"  Ingredients: {Ingredient.objects.count()}")
        self.stdout.write(f"  Pantry items: {PantryItem.objects.count()}")
        self.stdout.write(f"  Meta-recipes: {MetaRecipe.objects.count()}")
        self.stdout.write(f"  Slots: {Slot.objects.count()}")
        self.stdout.write(f"  Slot options: {SlotOption.objects.count()}")