Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added BakeryBackend/__pycache__/__init__.cpython-313.pyc
Binary file not shown.
Binary file not shown.
Binary file added BakeryBackend/__pycache__/main.cpython-313.pyc
Binary file not shown.
Binary file added BakeryBackend/__pycache__/models.cpython-313.pyc
Binary file not shown.
Binary file added BakeryBackend/__pycache__/schemas.cpython-313.pyc
Binary file not shown.
Binary file modified BakeryBackend/favorites.db
Binary file not shown.
24 changes: 21 additions & 3 deletions BakeryBackend/main.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
from fastapi import FastAPI
from BakeryBackend.routers import favorites
from BakeryBackend.routers import favorites, categories, items
from BakeryBackend.database import Base, engine

# Create all tables
Base.metadata.create_all(bind=engine)

app = FastAPI(title="Bakery Backend with Favorites")
app = FastAPI(
title="Enhanced Bakery Backend API",
description="Complete bakery management system with categories, items, and favorites",
version="2.0.0"
)

# Include all routers
app.include_router(categories.router)
app.include_router(items.router)
app.include_router(favorites.router)


@app.get("/")
def root():
return {
"message": "Enhanced Bakery Backend API",
"version": "2.0.0",
"endpoints": {
"categories": "/categories",
"items": "/items",
"favorites": "/favorites"
}
}
42 changes: 39 additions & 3 deletions BakeryBackend/models.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,46 @@
from sqlalchemy import Column, Integer, String
from sqlalchemy import Column, Integer, String, Float, Boolean, ForeignKey, DateTime, Text
from sqlalchemy.orm import relationship
from datetime import datetime
from BakeryBackend.database import Base

class Category(Base):
__tablename__ = "categories"

id = Column(Integer, primary_key=True, index=True)
name = Column(String(100), unique=True, nullable=False, index=True)
description = Column(Text, nullable=True)
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

items = relationship("Item", back_populates="category")

class Item(Base):
__tablename__ = "items"

id = Column(Integer, primary_key=True, index=True)
name = Column(String(200), nullable=False, index=True)
description = Column(Text, nullable=True)
price = Column(Float, nullable=False)
category_id = Column(Integer, ForeignKey("categories.id"), nullable=False)
image_url = Column(String(500), nullable=True)
is_available = Column(Boolean, default=True)
stock_quantity = Column(Integer, default=0)
ingredients = Column(Text, nullable=True)
allergens = Column(String(500), nullable=True)
preparation_time = Column(Integer, nullable=True) # in minutes
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

category = relationship("Category", back_populates="items")
favorites = relationship("Favorite", back_populates="item")

class Favorite(Base):
__tablename__ = "favorites"

id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, index=True)
item_id = Column(Integer, index=True)
item_name = Column(String, nullable=False)
item_id = Column(Integer, ForeignKey("items.id"), nullable=False)
created_at = Column(DateTime, default=datetime.utcnow)

item = relationship("Item", back_populates="favorites")
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
67 changes: 67 additions & 0 deletions BakeryBackend/routers/categories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from sqlalchemy.exc import IntegrityError
from typing import List
from BakeryBackend.database import get_db
from BakeryBackend.models import Category as CategoryModel
from BakeryBackend.schemas import Category, CategoryCreate, CategoryUpdate

router = APIRouter(prefix="/categories", tags=["Categories"])

@router.post("/", response_model=Category)
def create_category(category: CategoryCreate, db: Session = Depends(get_db)):
try:
db_category = CategoryModel(**category.dict())
db.add(db_category)
db.commit()
db.refresh(db_category)
return db_category
except IntegrityError:
raise HTTPException(status_code=409, detail="Category with this name already exists")

@router.get("/", response_model=List[Category])
def get_categories(skip: int = 0, limit: int = 100, active_only: bool = True, db: Session = Depends(get_db)):
query = db.query(CategoryModel)
if active_only:
query = query.filter(CategoryModel.is_active == True)
return query.offset(skip).limit(limit).all()

@router.get("/{category_id}", response_model=Category)
def get_category(category_id: int, db: Session = Depends(get_db)):
category = db.query(CategoryModel).filter(CategoryModel.id == category_id).first()
if not category:
raise HTTPException(status_code=404, detail="Category not found")
return category

@router.put("/{category_id}", response_model=Category)
def update_category(category_id: int, category_update: CategoryUpdate, db: Session = Depends(get_db)):
category = db.query(CategoryModel).filter(CategoryModel.id == category_id).first()
if not category:
raise HTTPException(status_code=404, detail="Category not found")

update_data = category_update.dict(exclude_unset=True)
if update_data:
for field, value in update_data.items():
setattr(category, field, value)

try:
db.commit()
db.refresh(category)
except IntegrityError:
raise HTTPException(status_code=409, detail="Category with this name already exists")

return category

@router.delete("/{category_id}")
def delete_category(category_id: int, db: Session = Depends(get_db)):
category = db.query(CategoryModel).filter(CategoryModel.id == category_id).first()
if not category:
raise HTTPException(status_code=404, detail="Category not found")

# Check if category has items
if category.items:
raise HTTPException(status_code=409, detail="Cannot delete category with existing items")

db.delete(category)
db.commit()
return {"message": "Category deleted successfully"}
34 changes: 26 additions & 8 deletions BakeryBackend/routers/favorites.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,29 @@
from sqlalchemy.orm import Session
from typing import List
from BakeryBackend.database import get_db
from BakeryBackend.models import Favorite as FavoriteModel
from BakeryBackend.schemas import Favorite
from BakeryBackend.models import Favorite as FavoriteModel, Item as ItemModel
from BakeryBackend.schemas import Favorite, FavoriteCreate

router = APIRouter(prefix="/favorites", tags=["Favorites"])


@router.post("/", response_model=Favorite)
def add_favorite(favorite: Favorite, db: Session = Depends(get_db)):
# Duplicate detection
def add_favorite(favorite: FavoriteCreate, db: Session = Depends(get_db)):
# Check if item exists
item = db.query(ItemModel).filter(ItemModel.id == favorite.item_id).first()
if not item:
raise HTTPException(status_code=404, detail="Item not found")

# Check for duplicate
existing = db.query(FavoriteModel).filter(
FavoriteModel.user_id == favorite.user_id,
FavoriteModel.item_id == favorite.item_id
).first()
if existing:
raise HTTPException(status_code=409, detail="Favorite already exists for this user and item.")

db_fav = FavoriteModel(
user_id=favorite.user_id,
item_id=favorite.item_id,
item_name=favorite.item_name
item_id=favorite.item_id
)
db.add(db_fav)
db.commit()
Expand All @@ -41,4 +45,18 @@ def delete_favorite(favorite_id: int, user_id: int, db: Session = Depends(get_db
raise HTTPException(status_code=403, detail="Not authorized to delete this favorite.")
db.delete(fav)
db.commit()
return {"message": "Favorite deleted successfully"}
return {"message": "Favorite deleted successfully"}

@router.delete("/user/{user_id}/item/{item_id}")
def remove_favorite_by_item(user_id: int, item_id: int, db: Session = Depends(get_db)):
"""Remove favorite by user_id and item_id (alternative to delete by favorite_id)"""
fav = db.query(FavoriteModel).filter(
FavoriteModel.user_id == user_id,
FavoriteModel.item_id == item_id
).first()
if not fav:
raise HTTPException(status_code=404, detail="Favorite not found")

db.delete(fav)
db.commit()
return {"message": "Favorite removed successfully"}
108 changes: 108 additions & 0 deletions BakeryBackend/routers/items.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from typing import List, Optional
from BakeryBackend.database import get_db
from BakeryBackend.models import Item as ItemModel, Category as CategoryModel
from BakeryBackend.schemas import Item, ItemCreate, ItemUpdate

router = APIRouter(prefix="/items", tags=["Items"])

@router.post("/", response_model=Item)
def create_item(item: ItemCreate, db: Session = Depends(get_db)):
# Check if category exists
category = db.query(CategoryModel).filter(CategoryModel.id == item.category_id).first()
if not category:
raise HTTPException(status_code=404, detail="Category not found")

db_item = ItemModel(**item.dict())
db.add(db_item)
db.commit()
db.refresh(db_item)
return db_item

@router.get("/", response_model=List[Item])
def get_items(
skip: int = 0,
limit: int = 100,
category_id: Optional[int] = None,
available_only: bool = True,
min_price: Optional[float] = None,
max_price: Optional[float] = None,
db: Session = Depends(get_db)
):
query = db.query(ItemModel)

if available_only:
query = query.filter(ItemModel.is_available == True)
if category_id:
query = query.filter(ItemModel.category_id == category_id)
if min_price is not None:
query = query.filter(ItemModel.price >= min_price)
if max_price is not None:
query = query.filter(ItemModel.price <= max_price)

return query.offset(skip).limit(limit).all()

@router.get("/{item_id}", response_model=Item)
def get_item(item_id: int, db: Session = Depends(get_db)):
item = db.query(ItemModel).filter(ItemModel.id == item_id).first()
if not item:
raise HTTPException(status_code=404, detail="Item not found")
return item

@router.put("/{item_id}", response_model=Item)
def update_item(item_id: int, item_update: ItemUpdate, db: Session = Depends(get_db)):
item = db.query(ItemModel).filter(ItemModel.id == item_id).first()
if not item:
raise HTTPException(status_code=404, detail="Item not found")

update_data = item_update.dict(exclude_unset=True)

# Check if category exists when updating category_id
if 'category_id' in update_data:
category = db.query(CategoryModel).filter(CategoryModel.id == update_data['category_id']).first()
if not category:
raise HTTPException(status_code=404, detail="Category not found")

if update_data:
for field, value in update_data.items():
setattr(item, field, value)
db.commit()
db.refresh(item)

return item

@router.delete("/{item_id}")
def delete_item(item_id: int, db: Session = Depends(get_db)):
item = db.query(ItemModel).filter(ItemModel.id == item_id).first()
if not item:
raise HTTPException(status_code=404, detail="Item not found")

db.delete(item)
db.commit()
return {"message": "Item deleted successfully"}

@router.patch("/{item_id}/availability")
def toggle_availability(item_id: int, available: bool, db: Session = Depends(get_db)):
item = db.query(ItemModel).filter(ItemModel.id == item_id).first()
if not item:
raise HTTPException(status_code=404, detail="Item not found")

item.is_available = available
db.commit()
db.refresh(item)
return {"message": f"Item availability updated to {available}"}

@router.patch("/{item_id}/stock")
def update_stock(item_id: int, quantity: int, db: Session = Depends(get_db)):
if quantity < 0:
raise HTTPException(status_code=400, detail="Stock quantity cannot be negative")

item = db.query(ItemModel).filter(ItemModel.id == item_id).first()
if not item:
raise HTTPException(status_code=404, detail="Item not found")

item.stock_quantity = quantity
db.commit()
db.refresh(item)
return {"message": f"Stock updated to {quantity}"}
Loading