groceries/backend/main.py
lasse 500cb8983c feat: implement shop CRUD operations and fix address deletion bug
- Add shop creation, editing, and deletion functionality
- Create AddShopModal and ConfirmDeleteModal components
- Add missing backend PUT/DELETE endpoints for shops
- Fix address field not clearing when edited to empty value
2025-05-25 12:56:56 +02:00

184 lines
6.6 KiB
Python

from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy.orm import Session
from typing import List
import models, schemas
from database import engine, get_db
# Create database tables
models.Base.metadata.create_all(bind=engine)
app = FastAPI(
title="Grocery Tracker API",
description="API for tracking grocery prices and shopping events",
version="1.0.0"
)
# CORS middleware for React frontend
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000", "http://localhost:5173"], # React dev servers
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Root endpoint
@app.get("/")
def read_root():
return {"message": "Grocery Tracker API", "version": "1.0.0"}
# Grocery endpoints
@app.post("/groceries/", response_model=schemas.Grocery)
def create_grocery(grocery: schemas.GroceryCreate, db: Session = Depends(get_db)):
db_grocery = models.Grocery(**grocery.dict())
db.add(db_grocery)
db.commit()
db.refresh(db_grocery)
return db_grocery
@app.get("/groceries/", response_model=List[schemas.Grocery])
def read_groceries(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
groceries = db.query(models.Grocery).offset(skip).limit(limit).all()
return groceries
@app.get("/groceries/{grocery_id}", response_model=schemas.Grocery)
def read_grocery(grocery_id: int, db: Session = Depends(get_db)):
grocery = db.query(models.Grocery).filter(models.Grocery.id == grocery_id).first()
if grocery is None:
raise HTTPException(status_code=404, detail="Grocery not found")
return grocery
@app.put("/groceries/{grocery_id}", response_model=schemas.Grocery)
def update_grocery(grocery_id: int, grocery_update: schemas.GroceryUpdate, db: Session = Depends(get_db)):
grocery = db.query(models.Grocery).filter(models.Grocery.id == grocery_id).first()
if grocery is None:
raise HTTPException(status_code=404, detail="Grocery not found")
update_data = grocery_update.dict(exclude_unset=True)
for field, value in update_data.items():
setattr(grocery, field, value)
db.commit()
db.refresh(grocery)
return grocery
@app.delete("/groceries/{grocery_id}")
def delete_grocery(grocery_id: int, db: Session = Depends(get_db)):
grocery = db.query(models.Grocery).filter(models.Grocery.id == grocery_id).first()
if grocery is None:
raise HTTPException(status_code=404, detail="Grocery not found")
db.delete(grocery)
db.commit()
return {"message": "Grocery deleted successfully"}
# Shop endpoints
@app.post("/shops/", response_model=schemas.Shop)
def create_shop(shop: schemas.ShopCreate, db: Session = Depends(get_db)):
db_shop = models.Shop(**shop.dict())
db.add(db_shop)
db.commit()
db.refresh(db_shop)
return db_shop
@app.get("/shops/", response_model=List[schemas.Shop])
def read_shops(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
shops = db.query(models.Shop).offset(skip).limit(limit).all()
return shops
@app.get("/shops/{shop_id}", response_model=schemas.Shop)
def read_shop(shop_id: int, db: Session = Depends(get_db)):
shop = db.query(models.Shop).filter(models.Shop.id == shop_id).first()
if shop is None:
raise HTTPException(status_code=404, detail="Shop not found")
return shop
@app.put("/shops/{shop_id}", response_model=schemas.Shop)
def update_shop(shop_id: int, shop_update: schemas.ShopUpdate, db: Session = Depends(get_db)):
shop = db.query(models.Shop).filter(models.Shop.id == shop_id).first()
if shop is None:
raise HTTPException(status_code=404, detail="Shop not found")
update_data = shop_update.dict()
for field, value in update_data.items():
setattr(shop, field, value)
db.commit()
db.refresh(shop)
return shop
@app.delete("/shops/{shop_id}")
def delete_shop(shop_id: int, db: Session = Depends(get_db)):
shop = db.query(models.Shop).filter(models.Shop.id == shop_id).first()
if shop is None:
raise HTTPException(status_code=404, detail="Shop not found")
db.delete(shop)
db.commit()
return {"message": "Shop deleted successfully"}
# Shopping Event endpoints
@app.post("/shopping-events/", response_model=schemas.ShoppingEventResponse)
def create_shopping_event(event: schemas.ShoppingEventCreate, db: Session = Depends(get_db)):
# Verify shop exists
shop = db.query(models.Shop).filter(models.Shop.id == event.shop_id).first()
if shop is None:
raise HTTPException(status_code=404, detail="Shop not found")
# Create shopping event
db_event = models.ShoppingEvent(
shop_id=event.shop_id,
date=event.date,
total_amount=event.total_amount,
notes=event.notes
)
db.add(db_event)
db.commit()
db.refresh(db_event)
# Add groceries to the event
for grocery_item in event.groceries:
grocery = db.query(models.Grocery).filter(models.Grocery.id == grocery_item.grocery_id).first()
if grocery is None:
raise HTTPException(status_code=404, detail=f"Grocery with id {grocery_item.grocery_id} not found")
# Insert into association table
db.execute(
models.shopping_event_groceries.insert().values(
shopping_event_id=db_event.id,
grocery_id=grocery_item.grocery_id,
amount=grocery_item.amount
)
)
db.commit()
db.refresh(db_event)
return db_event
@app.get("/shopping-events/", response_model=List[schemas.ShoppingEventResponse])
def read_shopping_events(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
events = db.query(models.ShoppingEvent).offset(skip).limit(limit).all()
return events
@app.get("/shopping-events/{event_id}", response_model=schemas.ShoppingEventResponse)
def read_shopping_event(event_id: int, db: Session = Depends(get_db)):
event = db.query(models.ShoppingEvent).filter(models.ShoppingEvent.id == event_id).first()
if event is None:
raise HTTPException(status_code=404, detail="Shopping event not found")
return event
# Statistics endpoints
@app.get("/stats/categories", response_model=List[schemas.CategoryStats])
def get_category_stats(db: Session = Depends(get_db)):
# This would need more complex SQL query - placeholder for now
return []
@app.get("/stats/shops", response_model=List[schemas.ShopStats])
def get_shop_stats(db: Session = Depends(get_db)):
# This would need more complex SQL query - placeholder for now
return []
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)