diff --git a/alembic/versions/20250429_145835_d97b1303_update_online_order.py b/alembic/versions/20250429_145835_d97b1303_update_online_order.py new file mode 100644 index 0000000..29efab8 --- /dev/null +++ b/alembic/versions/20250429_145835_d97b1303_update_online_order.py @@ -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') \ No newline at end of file diff --git a/endpoints/order.get.py b/endpoints/order.get.py index e69de29..f596a85 100644 --- a/endpoints/order.get.py +++ b/endpoints/order.get.py @@ -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 \ No newline at end of file diff --git a/helpers/online_order_helpers.py b/helpers/online_order_helpers.py new file mode 100644 index 0000000..48c40ba --- /dev/null +++ b/helpers/online_order_helpers.py @@ -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() \ No newline at end of file diff --git a/models/online_order.py b/models/online_order.py new file mode 100644 index 0000000..4e8bc35 --- /dev/null +++ b/models/online_order.py @@ -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") \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 596e6f3..db12c92 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,6 @@ sqlalchemy>=1.4.0 python-dotenv>=0.19.0 bcrypt>=3.2.0 alembic>=1.13.1 +jose +passlib +pydantic diff --git a/schemas/online_order.py b/schemas/online_order.py new file mode 100644 index 0000000..d0964ac --- /dev/null +++ b/schemas/online_order.py @@ -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 \ No newline at end of file