Files
live-campus-mcs-p-2027.2/Semaine_08/livrexpress/seed.py
T
gauvainboiche 3315cb2336 feat: Semaine 8
2026-05-11 09:25:19 +02:00

249 lines
11 KiB
Python

"""
seed_db.py, Peuplement de la base de données LivrExpress
==========================================================
Réinitialise et peuple livrexpress.db avec des données de démonstration.
Usage :
uv run python seed_db.py (depuis le dossier code/livexpress/)
Ce script illustre concrètement toutes les règles métier de OrderService :
RÈGLES (OrderService)
┌─────────────────────────────────────────────────────────────────┐
│ urgency_level → "normal" commande créée il y a < 30min │
"light_delay" entre 30 et 45min │
"severe_delay" > 45min sans livraison │
"delivered" commande livrée │
│ is_late → True si non livrée et créée il y a > 45min │
│ free_delivery → True si total >= 25.0 € │
│ is_premium → True si le client a >= 10 commandes au total │
└─────────────────────────────────────────────────────────────────┘
Le middleware simule l'utilisateur connecté avec customer_id = 1 (Marie).
"""
import sqlite3
from datetime import datetime, timedelta
DB_PATH = "livrexpress.db"
NOW = datetime.now()
# ─────────────────────────────────────────────────────────────────────────────
# Schéma
# ─────────────────────────────────────────────────────────────────────────────
SCHEMA = """
DROP TABLE IF EXISTS order_dishes;
DROP TABLE IF EXISTS orders;
DROP TABLE IF EXISTS dishes;
DROP TABLE IF EXISTS restaurants;
DROP TABLE IF EXISTS customers;
CREATE TABLE customers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL,
address TEXT NOT NULL
);
CREATE TABLE restaurants (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL
);
CREATE TABLE dishes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
price REAL NOT NULL,
restaurant_id INTEGER NOT NULL,
FOREIGN KEY (restaurant_id) REFERENCES restaurants(id)
);
CREATE TABLE orders (
id INTEGER PRIMARY KEY AUTOINCREMENT,
customer_id INTEGER NOT NULL,
restaurant_id INTEGER NOT NULL,
delivery_address TEXT NOT NULL,
created_at TEXT NOT NULL,
delivered_at TEXT,
FOREIGN KEY (customer_id) REFERENCES customers(id),
FOREIGN KEY (restaurant_id) REFERENCES restaurants(id)
);
CREATE TABLE order_dishes (
order_id INTEGER NOT NULL,
dish_id INTEGER NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(id),
FOREIGN KEY (dish_id) REFERENCES dishes(id)
);
"""
def seed():
conn = sqlite3.connect(DB_PATH)
conn.executescript(SCHEMA)
c = conn.cursor()
# ── Clients ──────────────────────────────────────────────────────────────
# Marie : 12 commandes au total → is_premium = True (seuil = 10)
# Lucas : 3 commandes au total → is_premium = False
c.execute("INSERT INTO customers (name, email, address) VALUES (?, ?, ?)",
("Marie Dupont", "marie@example.com", "12 rue de la Paix, Paris"))
marie_id = c.lastrowid
c.execute("INSERT INTO customers (name, email, address) VALUES (?, ?, ?)",
("Lucas Martin", "lucas@example.com", "5 avenue Montaigne, Paris"))
lucas_id = c.lastrowid
# ── Restaurants ──────────────────────────────────────────────────────────
c.execute("INSERT INTO restaurants (name) VALUES (?)", ("Chez Mario",))
mario_id = c.lastrowid
c.execute("INSERT INTO restaurants (name) VALUES (?)", ("Le Wok d'Or",))
wok_id = c.lastrowid
c.execute("INSERT INTO restaurants (name) VALUES (?)", ("Burger Palace",))
burger_id = c.lastrowid
# ── Plats ────────────────────────────────────────────────────────────────
dishes = [
("Margherita", 12.0, mario_id), # d1
("Quattro Stagioni", 14.5, mario_id), # d2
("Tiramisu", 6.0, mario_id), # d3
("Pad Thaï", 13.5, wok_id), # d4
("Nem croustillants", 8.0, wok_id), # d5
("Burger Classic", 11.0, burger_id), # d6
("Burger Double Bacon", 14.0, burger_id), # d7
("Frites maison", 4.5, burger_id), # d8
("Cheese Cake", 7.0, burger_id), # d9
]
dish_ids = []
for name, price, rid in dishes:
c.execute("INSERT INTO dishes (name, price, restaurant_id) VALUES (?, ?, ?)",
(name, price, rid))
dish_ids.append(c.lastrowid)
d1, d2, d3, d4, d5, d6, d7, d8, d9 = dish_ids
# ── Commandes pour Marie (customer_id=1) ─────────────────────────────────
# On couvre tous les cas des règles métier :
#
# urgency is_late free_del dishes total
# -------- ------- -------- ---------------------- -----
# normal False False Margherita 12.0
# normal False True Quattro + Tiramisu 20.5
# light_del False False Nem croustillants 8.0
# light_del False True Pad Thaï + Nem 21.5
# severe_del True False Burger Classic 11.0
# severe_del True True Burger x2 + Frites + CC 40.5
# delivered False True Margherita + Pad Thaï 25.5
order_specs = [
# (label, restaurant_id, created_at_offset_min, delivered_offset_min, dish_list)
("normal / pas chère", mario_id, -10, None, [d1]),
("normal / livraison ok",mario_id, -20, None, [d2, d3]),
("légère alerte", wok_id, -35, None, [d5]),
("légère alerte + gratu",wok_id, -38, None, [d4, d5]),
("retard / pas chère", burger_id, -60, None, [d6]),
("retard / livraison ok",burger_id, -90, None, [d7, d7, d8, d9]),
("livrée", mario_id, -50, -5, [d1, d4]),
]
marie_orders = []
for label, rest_id, offset_min, delivered_offset, dish_list in order_specs:
created = NOW + timedelta(minutes=offset_min)
delivered = (NOW + timedelta(minutes=delivered_offset)).isoformat() if delivered_offset else None
c.execute(
"INSERT INTO orders (customer_id, restaurant_id, delivery_address, created_at, delivered_at)"
" VALUES (?, ?, ?, ?, ?)",
(marie_id, rest_id, "12 rue de la Paix, Paris",
created.isoformat(), delivered)
)
order_id = c.lastrowid
for dish_id in dish_list:
c.execute("INSERT INTO order_dishes (order_id, dish_id) VALUES (?, ?)",
(order_id, dish_id))
total = sum(price for name, price, rid in dishes
for did in dish_list if did == dish_ids[dishes.index((name, price, rid))])
marie_orders.append((label, order_id, total, created, delivered, dish_list))
# Commandes historiques pour atteindre order_count >= 10 (Marie est premium)
# On en a déjà 7 ci-dessus, on en ajoute 5 dans le passé.
for i in range(5):
past = NOW - timedelta(days=30 + i)
c.execute(
"INSERT INTO orders (customer_id, restaurant_id, delivery_address, created_at, delivered_at)"
" VALUES (?, ?, ?, ?, ?)",
(marie_id, mario_id, "12 rue de la Paix, Paris",
past.isoformat(), (past + timedelta(minutes=35)).isoformat())
)
c.execute("INSERT INTO order_dishes (order_id, dish_id) VALUES (?, ?)",
(c.lastrowid, d1))
# ── Commandes pour Lucas (customer_id=2), non visibles via /my-orders ──
for i in range(3):
past = NOW - timedelta(days=5 + i)
c.execute(
"INSERT INTO orders (customer_id, restaurant_id, delivery_address, created_at, delivered_at)"
" VALUES (?, ?, ?, ?, ?)",
(lucas_id, burger_id, "5 avenue Montaigne, Paris",
past.isoformat(), (past + timedelta(minutes=40)).isoformat())
)
c.execute("INSERT INTO order_dishes (order_id, dish_id) VALUES (?, ?)",
(c.lastrowid, d6))
conn.commit()
conn.close()
# ── Résumé ──────────────────────────────────────────────────────────────
print()
print("" * 68)
print(" LivrExpress, Base de données peuplée")
print("" * 68)
print(f"\n Heure actuelle : {NOW.strftime('%H:%M:%S')}")
print(f"\n CLIENTS")
print(f" #1 Marie Dupont , 12 commandes au total → 🌟 PREMIUM (seuil ≥ 10)")
print(f" #2 Lucas Martin , 3 commandes au total → non premium")
print(f"\n Client simulé par le middleware : customer_id = 1 (Marie)")
print(f"\n COMMANDES VISIBLES sur /my-orders (Marie, 7 commandes récentes)")
print(f"\n {'scénario':<26} {'total':>7} {'créée il y a':>13} {'urgency_level':<14} badges")
print(" " + "" * 66)
urgency_labels = {
"normal": "normal ",
"light_delay": "⚠️ light_delay ",
"severe_delay": "🔴 severe_delay",
"delivered": "✅ delivered ",
}
for label, order_id, total, created, delivered, dish_list in marie_orders:
elapsed = (NOW - created).total_seconds() / 60
if delivered:
ul = "delivered"
elif elapsed > 45:
ul = "severe_delay"
elif elapsed > 30:
ul = "light_delay"
else:
ul = "normal"
badges = []
if not delivered and elapsed > 45:
badges.append("⏰ is_late")
if total >= 25.0:
badges.append("🚚 free_delivery")
if delivered:
badges.append("livrée")
age_str = f"{int(elapsed)}min ago"
print(f" {label:<26} {total:>6.1f}{age_str:>13} "
f"{urgency_labels[ul]} {', '.join(badges) if badges else ''}")
print(f"\n + 5 commandes anciennes (livrées, > 30 jours) pour atteindre order_count = 12")
print(f"\n COMMANDES Lucas (non visibles) : 3 commandes livrées")
print()
print(" ✓ Lancez l'app : uv run uvicorn main:app --reload")
print(" ✓ Commandes : http://localhost:8000/my-orders")
print("" * 68)
print()
if __name__ == "__main__":
seed()