wahnsinn vibe
This commit is contained in:
265
backend/core/seed.py
Normal file
265
backend/core/seed.py
Normal file
@@ -0,0 +1,265 @@
|
||||
"""Seed DB with admin + demo customer + categories + 12 clothing products."""
|
||||
from __future__ import annotations
|
||||
|
||||
from core.db import SessionLocal
|
||||
from core.events import event_bus
|
||||
from core.security import hash_password
|
||||
from core.settings_service import set_setting
|
||||
|
||||
from apps.auth.models import User
|
||||
from apps.catalog.models import Category, Product
|
||||
from apps.catalog.projector import rebuild_all
|
||||
|
||||
CATEGORIES = [
|
||||
{"slug": "oberteile", "name": {"de": "Oberteile", "en": "Tops"}, "sort_order": 1},
|
||||
{"slug": "hosen", "name": {"de": "Hosen", "en": "Pants"}, "sort_order": 2},
|
||||
{"slug": "schuhe", "name": {"de": "Schuhe", "en": "Shoes"}, "sort_order": 3},
|
||||
{"slug": "accessoires", "name": {"de": "Accessoires", "en": "Accessories"}, "sort_order": 4},
|
||||
]
|
||||
|
||||
|
||||
def _placeholder(color_hex: str, label: str) -> str:
|
||||
# Simple SVG data URL — zero external dependencies
|
||||
from urllib.parse import quote
|
||||
|
||||
svg = (
|
||||
f"<svg xmlns='http://www.w3.org/2000/svg' width='400' height='400' viewBox='0 0 400 400'>"
|
||||
f"<rect width='400' height='400' fill='#{color_hex}'/>"
|
||||
f"<text x='50%' y='50%' dominant-baseline='middle' text-anchor='middle' "
|
||||
f"font-family='Arial' font-size='26' fill='#ffffff'>{label}</text>"
|
||||
f"</svg>"
|
||||
)
|
||||
return "data:image/svg+xml;utf8," + quote(svg)
|
||||
|
||||
|
||||
PRODUCTS = [
|
||||
{
|
||||
"sku": "PULLI-GRUEN-M",
|
||||
"name": {"de": "Grüner Kuschelpulli", "en": "Green Cozy Sweater"},
|
||||
"description": {
|
||||
"de": "Weicher grüner Pullover aus Bio-Baumwolle, ideal für kühle Tage.",
|
||||
"en": "Soft green sweater made of organic cotton, perfect for chilly days.",
|
||||
},
|
||||
"price": 49.90,
|
||||
"stock": 20,
|
||||
"cat": "oberteile",
|
||||
"color": "green",
|
||||
"img": ("2e7d32", "Grüner Pulli"),
|
||||
},
|
||||
{
|
||||
"sku": "PULLI-BLAU-L",
|
||||
"name": {"de": "Blauer Rundhalspullover", "en": "Blue Crewneck Sweater"},
|
||||
"description": {
|
||||
"de": "Klassischer blauer Pullover mit Rundhalsausschnitt.",
|
||||
"en": "Classic blue crewneck sweater.",
|
||||
},
|
||||
"price": 42.00,
|
||||
"stock": 15,
|
||||
"cat": "oberteile",
|
||||
"color": "blue",
|
||||
"img": ("1565c0", "Blauer Pulli"),
|
||||
},
|
||||
{
|
||||
"sku": "TSHIRT-WHITE-M",
|
||||
"name": {"de": "Weißes Basic T-Shirt", "en": "White Basic T-Shirt"},
|
||||
"description": {
|
||||
"de": "Leichtes Basic-Shirt aus 100% Bio-Baumwolle.",
|
||||
"en": "Light basic shirt made of 100% organic cotton.",
|
||||
},
|
||||
"price": 14.90,
|
||||
"stock": 80,
|
||||
"cat": "oberteile",
|
||||
"color": "white",
|
||||
"img": ("f5f5f5", "Weißes Shirt"),
|
||||
},
|
||||
{
|
||||
"sku": "TSHIRT-BLACK-L",
|
||||
"name": {"de": "Schwarzes T-Shirt", "en": "Black T-Shirt"},
|
||||
"description": {
|
||||
"de": "Klassisches schwarzes Shirt, regular fit.",
|
||||
"en": "Classic black shirt, regular fit.",
|
||||
},
|
||||
"price": 15.90,
|
||||
"stock": 80,
|
||||
"cat": "oberteile",
|
||||
"color": "black",
|
||||
"img": ("212121", "Schwarzes Shirt"),
|
||||
},
|
||||
{
|
||||
"sku": "JACKE-OUTDOOR-M",
|
||||
"name": {"de": "Warme Outdoor-Jacke", "en": "Warm Outdoor Jacket"},
|
||||
"description": {
|
||||
"de": "Wasserabweisende, wärmende Jacke zum Wandern und Radeln im Herbst.",
|
||||
"en": "Water-repellent, warm jacket for hiking and cycling in autumn.",
|
||||
},
|
||||
"price": 129.00,
|
||||
"stock": 10,
|
||||
"cat": "oberteile",
|
||||
"color": "olive",
|
||||
"img": ("556b2f", "Outdoor-Jacke"),
|
||||
},
|
||||
{
|
||||
"sku": "JEANS-BLAU-32",
|
||||
"name": {"de": "Blaue Jeans Straight", "en": "Blue Straight Jeans"},
|
||||
"description": {
|
||||
"de": "Gerade geschnittene klassische Jeans in Dunkelblau.",
|
||||
"en": "Straight-cut classic jeans in dark blue.",
|
||||
},
|
||||
"price": 69.00,
|
||||
"stock": 40,
|
||||
"cat": "hosen",
|
||||
"color": "blue",
|
||||
"img": ("0d47a1", "Blaue Jeans"),
|
||||
},
|
||||
{
|
||||
"sku": "JEANS-SCHWARZ-34",
|
||||
"name": {"de": "Schwarze Slim Jeans", "en": "Black Slim Jeans"},
|
||||
"description": {
|
||||
"de": "Slim-Fit-Jeans in tiefem Schwarz, leicht elastisch.",
|
||||
"en": "Slim-fit jeans in deep black, slightly stretchy.",
|
||||
},
|
||||
"price": 74.00,
|
||||
"stock": 25,
|
||||
"cat": "hosen",
|
||||
"color": "black",
|
||||
"img": ("1b1b1b", "Schwarze Jeans"),
|
||||
},
|
||||
{
|
||||
"sku": "HOSE-WANDER-L",
|
||||
"name": {"de": "Wanderhose robust", "en": "Robust Hiking Pants"},
|
||||
"description": {
|
||||
"de": "Robuste Wanderhose für alle Jahreszeiten, wasserabweisend.",
|
||||
"en": "Robust hiking pants for all seasons, water-repellent.",
|
||||
},
|
||||
"price": 89.00,
|
||||
"stock": 18,
|
||||
"cat": "hosen",
|
||||
"color": "khaki",
|
||||
"img": ("6b8e23", "Wanderhose"),
|
||||
},
|
||||
{
|
||||
"sku": "SNEAKER-WEISS-42",
|
||||
"name": {"de": "Weiße Sneaker", "en": "White Sneakers"},
|
||||
"description": {
|
||||
"de": "Zeitlose weiße Sneaker für den Alltag.",
|
||||
"en": "Timeless white sneakers for everyday use.",
|
||||
},
|
||||
"price": 79.00,
|
||||
"stock": 30,
|
||||
"cat": "schuhe",
|
||||
"color": "white",
|
||||
"img": ("eeeeee", "Weiße Sneaker"),
|
||||
},
|
||||
{
|
||||
"sku": "WANDERSCHUH-43",
|
||||
"name": {"de": "Wanderschuhe warm", "en": "Warm Hiking Boots"},
|
||||
"description": {
|
||||
"de": "Warme Wanderschuhe mit guter Dämpfung und rutschfester Sohle.",
|
||||
"en": "Warm hiking boots with great cushioning and slip-resistant sole.",
|
||||
},
|
||||
"price": 149.00,
|
||||
"stock": 12,
|
||||
"cat": "schuhe",
|
||||
"color": "brown",
|
||||
"img": ("6d4c41", "Wanderschuhe"),
|
||||
},
|
||||
{
|
||||
"sku": "MUETZE-WOLLE",
|
||||
"name": {"de": "Wollmütze grün", "en": "Green Wool Beanie"},
|
||||
"description": {
|
||||
"de": "Warme grüne Wollmütze für kalte Tage.",
|
||||
"en": "Warm green wool beanie for cold days.",
|
||||
},
|
||||
"price": 19.90,
|
||||
"stock": 50,
|
||||
"cat": "accessoires",
|
||||
"color": "green",
|
||||
"img": ("388e3c", "Mütze"),
|
||||
},
|
||||
{
|
||||
"sku": "SCHAL-GRAU",
|
||||
"name": {"de": "Grauer Schal", "en": "Grey Scarf"},
|
||||
"description": {
|
||||
"de": "Weicher grauer Schal aus Merinowolle.",
|
||||
"en": "Soft grey scarf made of merino wool.",
|
||||
},
|
||||
"price": 29.00,
|
||||
"stock": 35,
|
||||
"cat": "accessoires",
|
||||
"color": "grey",
|
||||
"img": ("757575", "Grauer Schal"),
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def seed() -> None:
|
||||
db = SessionLocal()
|
||||
try:
|
||||
# Shop name setting
|
||||
if not db.query(User).filter_by(email="admin@example.com").first():
|
||||
set_setting(db, "core.shop_name", "Demo Shop")
|
||||
|
||||
# Users
|
||||
if not db.query(User).filter_by(email="admin@example.com").first():
|
||||
admin = User(
|
||||
email="admin@example.com",
|
||||
password_hash=hash_password("admin123"),
|
||||
role="admin",
|
||||
name="Admin",
|
||||
locale="de",
|
||||
)
|
||||
db.add(admin)
|
||||
if not db.query(User).filter_by(email="kunde@example.com").first():
|
||||
customer = User(
|
||||
email="kunde@example.com",
|
||||
password_hash=hash_password("kunde123"),
|
||||
role="customer",
|
||||
name="Demo Kunde",
|
||||
locale="de",
|
||||
)
|
||||
db.add(customer)
|
||||
db.commit()
|
||||
|
||||
# Categories
|
||||
cats_by_slug: dict[str, Category] = {}
|
||||
for c in CATEGORIES:
|
||||
row = db.query(Category).filter_by(slug=c["slug"]).first()
|
||||
if not row:
|
||||
row = Category(slug=c["slug"], name=c["name"], sort_order=c["sort_order"])
|
||||
db.add(row)
|
||||
db.commit()
|
||||
db.refresh(row)
|
||||
event_bus.publish("category.created", {"id": row.id}, db=db)
|
||||
cats_by_slug[c["slug"]] = row
|
||||
|
||||
# Products
|
||||
for pd in PRODUCTS:
|
||||
if db.query(Product).filter_by(sku=pd["sku"]).first():
|
||||
continue
|
||||
image = _placeholder(*pd["img"])
|
||||
p = Product(
|
||||
sku=pd["sku"],
|
||||
name=pd["name"],
|
||||
description=pd["description"],
|
||||
price=pd["price"],
|
||||
currency="EUR",
|
||||
stock=pd["stock"],
|
||||
active=True,
|
||||
image_url=image,
|
||||
category_id=cats_by_slug[pd["cat"]].id,
|
||||
attributes={"color": pd["color"]},
|
||||
)
|
||||
db.add(p)
|
||||
db.commit()
|
||||
db.refresh(p)
|
||||
event_bus.publish("product.created", {"id": p.id, "sku": p.sku}, db=db)
|
||||
|
||||
# Rebuild Redis cache (idempotent)
|
||||
rebuild_all(db)
|
||||
print("Seed complete.")
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
seed()
|
||||
Reference in New Issue
Block a user