feat: Implement online food ordering system (auto-linted)

This commit is contained in:
Backend IM Bot 2025-04-29 14:59:20 +00:00
parent 51b935f990
commit c8d3771add
6 changed files with 349 additions and 0 deletions

View File

@ -0,0 +1,45 @@
"""create tables for online_orders and order_items
Revision ID: 5b9e6f3a8d4c
Revises: 0001
Create Date: 2023-05-23 10:15:12.844940
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.sql import func
import uuid
# revision identifiers, used by Alembic.
revision = '5b9e6f3a8d4c'
down_revision = '0001'
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
'online_orders',
sa.Column('id', sa.String(36), primary_key=True, default=lambda: str(uuid.uuid4())),
sa.Column('order_number', sa.String(), nullable=False, unique=True, index=True),
sa.Column('customer_name', sa.String(), nullable=False),
sa.Column('customer_email', sa.String(), nullable=False),
sa.Column('customer_phone', sa.String(), nullable=False),
sa.Column('delivery_address', sa.String(), nullable=False),
sa.Column('total_amount', sa.Float(), nullable=False),
sa.Column('status', sa.String(), nullable=False, server_default='pending'),
sa.Column('created_at', sa.DateTime(), server_default=func.now()),
sa.Column('updated_at', sa.DateTime(), server_default=func.now(), onupdate=func.now())
)
op.create_table(
'order_items',
sa.Column('id', sa.String(36), primary_key=True, default=lambda: str(uuid.uuid4())),
sa.Column('order_id', sa.String(36), sa.ForeignKey('online_orders.id'), nullable=False),
sa.Column('product_name', sa.String(), nullable=False),
sa.Column('product_price', sa.Float(), nullable=False),
sa.Column('quantity', sa.Integer(), nullable=False),
sa.Column('created_at', sa.DateTime(), server_default=func.now()),
sa.Column('updated_at', sa.DateTime(), server_default=func.now(), onupdate=func.now())
)
def downgrade():
op.drop_table('order_items')
op.drop_table('online_orders')

View File

@ -0,0 +1,13 @@
from fastapi import APIRouter, Depends
from typing import List
from sqlalchemy.orm import Session
from core.database import get_db
from schemas.online_order import OnlineOrderSchema
from helpers.online_order_helpers import get_all_online_orders
router = APIRouter()
@router.get("/order", status_code=200, response_model=List[OnlineOrderSchema])
async def get_orders(db: Session = Depends(get_db)):
orders = get_all_online_orders(db)
return orders

View File

@ -0,0 +1,180 @@
from typing import List, Optional
from uuid import UUID
from sqlalchemy.orm import Session
from sqlalchemy import or_, and_
from models.online_order import OnlineOrder, OrderItem
from schemas.online_order import OnlineOrderCreate, OnlineOrderUpdate, OrderItemCreate, OrderItemUpdate
def get_online_order_by_id(db: Session, order_id: UUID) -> Optional[OnlineOrder]:
"""
Retrieves an online order by its ID.
Args:
db (Session): The database session.
order_id (UUID): The ID of the online order to retrieve.
Returns:
Optional[OnlineOrder]: The online order object if found, otherwise None.
"""
return db.query(OnlineOrder).filter(OnlineOrder.id == order_id).first()
def get_all_online_orders(db: Session) -> List[OnlineOrder]:
"""
Retrieves all online orders from the database.
Args:
db (Session): The database session.
Returns:
List[OnlineOrder]: A list of all online order objects.
"""
return db.query(OnlineOrder).all()
def create_online_order(db: Session, order_data: OnlineOrderCreate) -> OnlineOrder:
"""
Creates a new online order in the database.
Args:
db (Session): The database session.
order_data (OnlineOrderCreate): The data for the online order to create.
Returns:
OnlineOrder: The newly created online order object.
"""
db_order = OnlineOrder(**order_data.dict())
db.add(db_order)
db.commit()
db.refresh(db_order)
return db_order
def update_online_order(db: Session, order_id: UUID, order_data: OnlineOrderUpdate) -> Optional[OnlineOrder]:
"""
Updates an existing online order in the database.
Args:
db (Session): The database session.
order_id (UUID): The ID of the online order to update.
order_data (OnlineOrderUpdate): The updated data for the online order.
Returns:
Optional[OnlineOrder]: The updated online order object if found, otherwise None.
"""
db_order = get_online_order_by_id(db, order_id)
if not db_order:
return None
for field, value in order_data.dict(exclude_unset=True).items():
setattr(db_order, field, value)
db.commit()
db.refresh(db_order)
return db_order
def delete_online_order(db: Session, order_id: UUID) -> bool:
"""
Deletes an online order from the database.
Args:
db (Session): The database session.
order_id (UUID): The ID of the online order to delete.
Returns:
bool: True if the online order was successfully deleted, False otherwise.
"""
db_order = get_online_order_by_id(db, order_id)
if not db_order:
return False
db.delete(db_order)
db.commit()
return True
def create_order_item(db: Session, order_id: UUID, item_data: OrderItemCreate) -> OrderItem:
"""
Creates a new order item for an online order.
Args:
db (Session): The database session.
order_id (UUID): The ID of the online order to add the item to.
item_data (OrderItemCreate): The data for the order item to create.
Returns:
OrderItem: The newly created order item object.
"""
db_order = get_online_order_by_id(db, order_id)
if not db_order:
raise ValueError(f"Online order with ID {order_id} not found.")
db_item = OrderItem(**item_data.dict(), order_id=order_id)
db.add(db_item)
db.commit()
db.refresh(db_item)
return db_item
def update_order_item(db: Session, item_id: UUID, item_data: OrderItemUpdate) -> Optional[OrderItem]:
"""
Updates an existing order item.
Args:
db (Session): The database session.
item_id (UUID): The ID of the order item to update.
item_data (OrderItemUpdate): The updated data for the order item.
Returns:
Optional[OrderItem]: The updated order item object if found, otherwise None.
"""
db_item = db.query(OrderItem).filter(OrderItem.id == item_id).first()
if not db_item:
return None
for field, value in item_data.dict(exclude_unset=True).items():
setattr(db_item, field, value)
db.commit()
db.refresh(db_item)
return db_item
def delete_order_item(db: Session, item_id: UUID) -> bool:
"""
Deletes an order item from the database.
Args:
db (Session): The database session.
item_id (UUID): The ID of the order item to delete.
Returns:
bool: True if the order item was successfully deleted, False otherwise.
"""
db_item = db.query(OrderItem).filter(OrderItem.id == item_id).first()
if not db_item:
return False
db.delete(db_item)
db.commit()
return True
def search_online_orders(db: Session, query: str) -> List[OnlineOrder]:
"""
Searches for online orders based on a search query.
Args:
db (Session): The database session.
query (str): The search query string.
Returns:
List[OnlineOrder]: A list of online order objects matching the search query.
"""
search_pattern = f"%{query}%"
return db.query(OnlineOrder).filter(
or_(
OnlineOrder.order_number.ilike(search_pattern),
OnlineOrder.customer_name.ilike(search_pattern),
OnlineOrder.customer_email.ilike(search_pattern),
OnlineOrder.customer_phone.ilike(search_pattern),
OnlineOrder.delivery_address.ilike(search_pattern),
and_(
OrderItem.product_name.ilike(search_pattern),
OrderItem.order_id == OnlineOrder.id,
),
)
).all()

44
models/online_order.py Normal file
View File

@ -0,0 +1,44 @@
from sqlalchemy import Column, String, Integer, Float, DateTime, ForeignKey, Enum
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from core.database import Base
import uuid
import enum
class OrderStatus(str, enum.Enum):
PENDING = "pending"
ACCEPTED = "accepted"
PREPARING = "preparing"
READY = "ready"
DELIVERED = "delivered"
CANCELED = "canceled"
class OnlineOrder(Base):
__tablename__ = "online_orders"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
order_number = Column(String, unique=True, nullable=False, index=True)
customer_name = Column(String, nullable=False)
customer_email = Column(String, nullable=False)
customer_phone = Column(String, nullable=False)
delivery_address = Column(String, nullable=False)
total_amount = Column(Float, nullable=False)
status = Column(Enum(OrderStatus), nullable=False, default=OrderStatus.PENDING)
created_at = Column(DateTime, default=func.now())
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
order_items = relationship("OrderItem", back_populates="order")
class OrderItem(Base):
__tablename__ = "order_items"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
order_id = Column(UUID(as_uuid=True), ForeignKey("online_orders.id"), nullable=False)
product_name = Column(String, nullable=False)
product_price = Column(Float, nullable=False)
quantity = Column(Integer, nullable=False)
created_at = Column(DateTime, default=func.now())
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
order = relationship("OnlineOrder", back_populates="order_items")

View File

@ -7,3 +7,6 @@ sqlalchemy>=1.4.0
python-dotenv>=0.19.0
bcrypt>=3.2.0
alembic>=1.13.1
jose
passlib
pydantic

64
schemas/online_order.py Normal file
View File

@ -0,0 +1,64 @@
from pydantic import BaseModel, EmailStr
from typing import Optional
from datetime import datetime
import uuid
import enum
class OrderStatus(str, enum.Enum):
PENDING = "pending"
ACCEPTED = "accepted"
PREPARING = "preparing"
READY = "ready"
DELIVERED = "delivered"
CANCELED = "canceled"
class OnlineOrderBase(BaseModel):
order_number: str
customer_name: str
customer_email: EmailStr
customer_phone: str
delivery_address: str
total_amount: float
status: OrderStatus = OrderStatus.PENDING
class OnlineOrderCreate(OnlineOrderBase):
pass
class OnlineOrderUpdate(OnlineOrderBase):
order_number: Optional[str] = None
customer_name: Optional[str] = None
customer_email: Optional[EmailStr] = None
customer_phone: Optional[str] = None
delivery_address: Optional[str] = None
total_amount: Optional[float] = None
status: Optional[OrderStatus] = None
class OnlineOrderSchema(OnlineOrderBase):
id: uuid.UUID
created_at: datetime
updated_at: datetime
class Config:
orm_mode = True
class OrderItemBase(BaseModel):
product_name: str
product_price: float
quantity: int
class OrderItemCreate(OrderItemBase):
pass
class OrderItemUpdate(OrderItemBase):
product_name: Optional[str] = None
product_price: Optional[float] = None
quantity: Optional[int] = None
class OrderItemSchema(OrderItemBase):
id: uuid.UUID
order_id: uuid.UUID
created_at: datetime
updated_at: datetime
class Config:
orm_mode = True