diff --git a/pos_backend/.env b/pos_backend/.env deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/pos_backend/__init__.py b/pos_backend/__init__.py deleted file mode 100644 index 1142525324061a2d96d63fb00bb81ee0216eed06..0000000000000000000000000000000000000000 --- a/pos_backend/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" -POS Backend Package -""" diff --git a/pos_backend/__pycache__/main.cpython-312.pyc b/pos_backend/__pycache__/main.cpython-312.pyc deleted file mode 100644 index b4b19f6e3f01604960902bbafb644857ed7d8f85..0000000000000000000000000000000000000000 Binary files a/pos_backend/__pycache__/main.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/__init__.py b/pos_backend/app/__init__.py deleted file mode 100644 index eba3194f2c1aa063b0f44bb552cb3de74383fa28..0000000000000000000000000000000000000000 --- a/pos_backend/app/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -""" -POS Backend Application Package -""" diff --git a/pos_backend/app/__pycache__/__init__.cpython-312.pyc b/pos_backend/app/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 5fe2ba179b3ecc6efbf8aa6d99f28499ac1a85a9..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/api/__init__.py b/pos_backend/app/api/__init__.py deleted file mode 100644 index 5e2cb4b414f15d61d21fcf74f027d5f9a801d483..0000000000000000000000000000000000000000 --- a/pos_backend/app/api/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Empty file to mark directory as Python package diff --git a/pos_backend/app/api/__pycache__/__init__.cpython-312.pyc b/pos_backend/app/api/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 07a0fc7b573fb5195ce1d362eda6fc7c17214588..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/api/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/api/api_v1/__init__.py b/pos_backend/app/api/api_v1/__init__.py deleted file mode 100644 index 5e2cb4b414f15d61d21fcf74f027d5f9a801d483..0000000000000000000000000000000000000000 --- a/pos_backend/app/api/api_v1/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Empty file to mark directory as Python package diff --git a/pos_backend/app/api/api_v1/__pycache__/__init__.cpython-312.pyc b/pos_backend/app/api/api_v1/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 93ae6e8a69922f25dccce35a317924c2a39795ab..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/api/api_v1/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/api/api_v1/__pycache__/api.cpython-312.pyc b/pos_backend/app/api/api_v1/__pycache__/api.cpython-312.pyc deleted file mode 100644 index 943bb5dfd91cf17b21f158df9103e4188341646f..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/api/api_v1/__pycache__/api.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/api/api_v1/api.py b/pos_backend/app/api/api_v1/api.py deleted file mode 100644 index 297dd0bc35760b583224c04db4547ddd1f1d25e1..0000000000000000000000000000000000000000 --- a/pos_backend/app/api/api_v1/api.py +++ /dev/null @@ -1,10 +0,0 @@ -from fastapi import APIRouter -from app.api.api_v1.endpoints import auth, menu, orders, payments, reports - -api_router = APIRouter() - -api_router.include_router(auth.router, prefix="/auth", tags=["auth"]) -api_router.include_router(menu.router, prefix="/menu", tags=["menu"]) -api_router.include_router(orders.router, prefix="/orders", tags=["orders"]) -api_router.include_router(payments.router, prefix="/payments", tags=["payments"]) -api_router.include_router(reports.router, prefix="/reports", tags=["reports"]) diff --git a/pos_backend/app/api/api_v1/endpoints/__init__.py b/pos_backend/app/api/api_v1/endpoints/__init__.py deleted file mode 100644 index 5e2cb4b414f15d61d21fcf74f027d5f9a801d483..0000000000000000000000000000000000000000 --- a/pos_backend/app/api/api_v1/endpoints/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Empty file to mark directory as Python package diff --git a/pos_backend/app/api/api_v1/endpoints/__pycache__/__init__.cpython-312.pyc b/pos_backend/app/api/api_v1/endpoints/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 4a364c39575b993e183b65c102f6bccc24768d34..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/api/api_v1/endpoints/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/api/api_v1/endpoints/__pycache__/auth.cpython-312.pyc b/pos_backend/app/api/api_v1/endpoints/__pycache__/auth.cpython-312.pyc deleted file mode 100644 index 7a1a1a4a768c83710713b02ee781c22cc34383d8..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/api/api_v1/endpoints/__pycache__/auth.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/api/api_v1/endpoints/__pycache__/menu.cpython-312.pyc b/pos_backend/app/api/api_v1/endpoints/__pycache__/menu.cpython-312.pyc deleted file mode 100644 index 2e997061e291a22714814fd9f4c14cbc8756fce7..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/api/api_v1/endpoints/__pycache__/menu.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/api/api_v1/endpoints/__pycache__/orders.cpython-312.pyc b/pos_backend/app/api/api_v1/endpoints/__pycache__/orders.cpython-312.pyc deleted file mode 100644 index edfffd5e067dc23f5f59db05a1842e5b913480eb..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/api/api_v1/endpoints/__pycache__/orders.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/api/api_v1/endpoints/__pycache__/payments.cpython-312.pyc b/pos_backend/app/api/api_v1/endpoints/__pycache__/payments.cpython-312.pyc deleted file mode 100644 index d043688962cd5fecfa84098c06f9d535179abf9c..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/api/api_v1/endpoints/__pycache__/payments.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/api/api_v1/endpoints/__pycache__/reports.cpython-312.pyc b/pos_backend/app/api/api_v1/endpoints/__pycache__/reports.cpython-312.pyc deleted file mode 100644 index 6508ac4ed4eb4e4caec0b20a8c9723385fd95f26..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/api/api_v1/endpoints/__pycache__/reports.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/api/api_v1/endpoints/auth.py b/pos_backend/app/api/api_v1/endpoints/auth.py deleted file mode 100644 index 5da2b14aba3788c630ca5aa68601daede7542822..0000000000000000000000000000000000000000 --- a/pos_backend/app/api/api_v1/endpoints/auth.py +++ /dev/null @@ -1,13 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException -from app.services.auth_service import authenticate_user, create_access_token -from app.models.auth import LoginRequest, LoginResponse - -router = APIRouter() - -@router.post("/login", response_model=LoginResponse) -async def login(user_data: LoginRequest): - user = await authenticate_user(user_data.email, user_data.password) - if not user: - raise HTTPException(status_code=401, detail="Invalid credentials") - access_token = create_access_token(data={"sub": user.email}) - return LoginResponse(access_token=access_token, token_type="bearer", user=user) diff --git a/pos_backend/app/api/api_v1/endpoints/menu.py b/pos_backend/app/api/api_v1/endpoints/menu.py deleted file mode 100644 index 49f0d1bfec4bec81771c2dede8a14720d72ef136..0000000000000000000000000000000000000000 --- a/pos_backend/app/api/api_v1/endpoints/menu.py +++ /dev/null @@ -1,19 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException, status -from app.services.menu_service import MenuService -from app.models.menu import MenuItem, Category -from typing import List - -router = APIRouter() -menu_service = MenuService() - -@router.get("/items", response_model=List[MenuItem]) -async def get_menu_items(): - return await menu_service.get_menu_items() - -@router.post("/items", response_model=MenuItem, status_code=status.HTTP_201_CREATED) -async def create_menu_item(item: MenuItem): - return await menu_service.create_menu_item(item) - -@router.get("/categories", response_model=List[Category]) -async def get_categories(): - return await menu_service.get_categories() diff --git a/pos_backend/app/api/api_v1/endpoints/orders.py b/pos_backend/app/api/api_v1/endpoints/orders.py deleted file mode 100644 index e890145e56a44bd60d391c4610aa4fff0e230b38..0000000000000000000000000000000000000000 --- a/pos_backend/app/api/api_v1/endpoints/orders.py +++ /dev/null @@ -1,36 +0,0 @@ -from fastapi import APIRouter, HTTPException, status, Depends -from app.services.order_service import OrderService -from app.models.orders import Order, OrderStatus -from typing import List - -router = APIRouter() - -@router.post("/", response_model=Order, status_code=status.HTTP_201_CREATED) -async def create_order(order: Order, service: OrderService = Depends(OrderService)): - return await service.create_order(order) - -@router.get("/{order_id}", response_model=Order) -async def get_order(order_id: int, service: OrderService = Depends(OrderService)): - return await service.get_order(order_id) - -@router.put("/{order_id}/status", response_model=Order) -async def update_order_status( - order_id: int, - status: OrderStatus, - service: OrderService = Depends(OrderService) -): - return await service.update_status(order_id, status) - -@router.get("/status/{status}", response_model=List[Order]) -async def get_orders_by_status( - status: OrderStatus, - service: OrderService = Depends(OrderService) -): - return await service.get_orders_by_status(status) - -@router.get("/daily/{date}", response_model=List[Order]) -async def get_daily_orders( - date: str, - service: OrderService = Depends(OrderService) -): - return await service.get_daily_orders(date) diff --git a/pos_backend/app/api/api_v1/endpoints/payments.py b/pos_backend/app/api/api_v1/endpoints/payments.py deleted file mode 100644 index 3c1db1e33744635538ccd947b687ac409d6622c7..0000000000000000000000000000000000000000 --- a/pos_backend/app/api/api_v1/endpoints/payments.py +++ /dev/null @@ -1,27 +0,0 @@ -from fastapi import APIRouter, HTTPException, status, Depends -from app.services.payment_service import PaymentService -from app.models.payment import Payment, PaymentStatus - -router = APIRouter() - -@router.post("/", response_model=Payment, status_code=status.HTTP_201_CREATED) -async def process_payment( - payment: Payment, - service: PaymentService = Depends(PaymentService) -): - return await service.process_payment(payment) - -@router.get("/{payment_id}", response_model=Payment) -async def get_payment( - payment_id: int, - service: PaymentService = Depends(PaymentService) -): - return await service.get_payment(payment_id) - -@router.put("/{payment_id}/status", response_model=Payment) -async def update_payment_status( - payment_id: int, - status: PaymentStatus, - service: PaymentService = Depends(PaymentService) -): - return await service.update_status(payment_id, status) diff --git a/pos_backend/app/api/api_v1/endpoints/reports.py b/pos_backend/app/api/api_v1/endpoints/reports.py deleted file mode 100644 index dddab99a2e2640a4348bbf7d08da7731de8173f8..0000000000000000000000000000000000000000 --- a/pos_backend/app/api/api_v1/endpoints/reports.py +++ /dev/null @@ -1,36 +0,0 @@ -from fastapi import APIRouter, Depends -from app.services.report_service import ReportService -from app.models.reports import DailyReport, WeeklyReport -from datetime import date -from fastapi.responses import JSONResponse -from fastapi import HTTPException, status - -router = APIRouter() - -@router.get("/daily/{date}", response_model=DailyReport) -async def get_daily_report( - date: date, - service: ReportService = Depends(ReportService) -): - try: - return await service.generate_daily_report(date.isoformat()) - except Exception as e: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=f"Failed to generate daily report: {str(e)}" - ) - -@router.get("/weekly", response_model=WeeklyReport) -async def get_weekly_report( - end_date: date = None, - service: ReportService = Depends(ReportService) -): - try: - return await service.generate_weekly_report( - end_date.isoformat() if end_date else None - ) - except Exception as e: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=f"Failed to generate weekly report: {str(e)}" - ) diff --git a/pos_backend/app/core/__pycache__/config.cpython-312.pyc b/pos_backend/app/core/__pycache__/config.cpython-312.pyc deleted file mode 100644 index d455e50088e2231cbd3baf72b83edb0969904ba9..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/core/__pycache__/config.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/core/auth.py b/pos_backend/app/core/auth.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/pos_backend/app/core/config.py b/pos_backend/app/core/config.py deleted file mode 100644 index ee658b93ac0bbec52e5e64d1fd4a8ed056158960..0000000000000000000000000000000000000000 --- a/pos_backend/app/core/config.py +++ /dev/null @@ -1,15 +0,0 @@ -from pydantic_settings import BaseSettings - -class Settings(BaseSettings): - PROJECT_NAME: str = "POS Backend" - API_V1_STR: str = "/api/v1" - SECRET_KEY: str = "your-secret-key-here" - ALGORITHM: str = "HS256" - ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 - REFRESH_TOKEN_EXPIRE_DAYS: int = 7 - DATABASE_URL: str = "postgresql+asyncpg://postgres.juycnkjuzylnbruwaqmp:Lovyelias5584.@aws-0-eu-central-1.pooler.supabase.com:5432/postgres" - - class Config: - env_file = ".env" - -settings = Settings() \ No newline at end of file diff --git a/pos_backend/app/core/database.py b/pos_backend/app/core/database.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/pos_backend/app/core/dependencies.py b/pos_backend/app/core/dependencies.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/pos_backend/app/db/__pycache__/crud.cpython-312.pyc b/pos_backend/app/db/__pycache__/crud.cpython-312.pyc deleted file mode 100644 index 8abffce963f1332d49adb26d9a3685690352aba7..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/db/__pycache__/crud.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/db/__pycache__/database.cpython-312.pyc b/pos_backend/app/db/__pycache__/database.cpython-312.pyc deleted file mode 100644 index b0fb733cde5c8e863d757326f776757071751cde..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/db/__pycache__/database.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/db/crud.py b/pos_backend/app/db/crud.py deleted file mode 100644 index 8d34433382433ae44bb876be728a2075c8d842f8..0000000000000000000000000000000000000000 --- a/pos_backend/app/db/crud.py +++ /dev/null @@ -1,200 +0,0 @@ -from sqlalchemy.ext.asyncio import AsyncSession -from sqlalchemy import select, update, delete, and_, func -from sqlalchemy.orm import selectinload -from ..models.database import MenuItem, Order, Payment, User, Category, OrderItem -from ..models.orders import OrderStatus -from ..models.payment import PaymentStatus -from typing import List, Optional, Dict -from datetime import datetime - -# User Operations -async def get_user_by_email(db: AsyncSession, email: str) -> Optional[User]: - result = await db.execute(select(User).where(User.email == email)) - return result.scalar_one_or_none() - -async def create_user(db: AsyncSession, user: User) -> User: - db.add(user) - await db.commit() - await db.refresh(user) - return user - -# Menu Operations -async def get_menu_items(db: AsyncSession) -> List[MenuItem]: - result = await db.execute( - select(MenuItem).options(selectinload(MenuItem.category)) - ) - return result.scalars().all() - -async def get_menu_item_by_id(db: AsyncSession, item_id: int) -> Optional[MenuItem]: - result = await db.execute( - select(MenuItem) - .options(selectinload(MenuItem.category)) - .where(MenuItem.id == item_id) - ) - return result.scalar_one_or_none() - -async def create_menu_item_db(db: AsyncSession, item: MenuItem) -> MenuItem: - db.add(item) - await db.commit() - await db.refresh(item) - return item - -async def update_menu_item_db(db: AsyncSession, item_id: int, item: MenuItem) -> Optional[MenuItem]: - query = update(MenuItem).where(MenuItem.id == item_id).values(**item.dict(exclude={'id'})) - await db.execute(query) - await db.commit() - return await get_menu_item_by_id(db, item_id) - -async def delete_menu_item_db(db: AsyncSession, item_id: int) -> bool: - query = delete(MenuItem).where(MenuItem.id == item_id) - result = await db.execute(query) - await db.commit() - return result.rowcount > 0 - -async def get_categories_db(db: AsyncSession) -> List[Category]: - result = await db.execute(select(Category)) - return result.scalars().all() - -# Order Operations -async def create_order_db(db: AsyncSession, order: Order) -> Order: - db.add(order) - await db.commit() - await db.refresh(order) - return order - -async def get_order_by_id(db: AsyncSession, order_id: int) -> Optional[Order]: - result = await db.execute( - select(Order) - .options(selectinload(Order.items)) - .where(Order.id == order_id) - ) - return result.scalar_one_or_none() - -async def update_order_status(db: AsyncSession, order_id: int, new_status: OrderStatus) -> Order: - """Update the status of an order.""" - query = update(Order).where(Order.id == order_id).values(status=new_status) - await db.execute(query) - await db.commit() - return await get_order_by_id(db, order_id) - -async def get_orders_by_status(db: AsyncSession, status: OrderStatus) -> List[Order]: - """Get all orders with a specific status.""" - result = await db.execute( - select(Order) - .options(selectinload(Order.items)) - .where(Order.status == status) - .order_by(Order.created_at.desc()) - ) - return result.scalars().all() - -async def get_orders_by_date_range(db: AsyncSession, start_date: str, end_date: str) -> List[Order]: - """Get orders within a date range.""" - start = datetime.strptime(start_date, "%Y-%m-%d") - end = datetime.strptime(end_date, "%Y-%m-%d").replace(hour=23, minute=59, second=59) - - result = await db.execute( - select(Order) - .options(selectinload(Order.items)) - .where(and_(Order.created_at >= start, Order.created_at <= end)) - .order_by(Order.created_at.desc()) - ) - return result.scalars().all() - -# Payment Operations -async def create_payment_db(db: AsyncSession, payment: Payment) -> Payment: - db.add(payment) - await db.commit() - await db.refresh(payment) - return payment - -async def get_payment_by_id(db: AsyncSession, payment_id: int) -> Optional[Payment]: - result = await db.execute(select(Payment).where(Payment.id == payment_id)) - return result.scalar_one_or_none() - -async def update_payment_status(db: AsyncSession, payment_id: int, new_status: PaymentStatus) -> Optional[Payment]: - """Update the status of a payment transaction.""" - query = ( - update(Payment) - .where(Payment.id == payment_id) - .values( - status=new_status, - updated_at=datetime.utcnow() - ) - ) - await db.execute(query) - await db.commit() - return await get_payment_by_id(db, payment_id) - -# Report Operations -async def get_sales_by_date_range(db: AsyncSession, start_date: str, end_date: str) -> List[Order]: - """Get all sales within a date range.""" - start = datetime.fromisoformat(start_date) - end = datetime.fromisoformat(end_date).replace(hour=23, minute=59, second=59) - - result = await db.execute( - select(Order) - .options(selectinload(Order.items)) - .where( - and_( - Order.created_at >= start, - Order.created_at <= end, - Order.status == OrderStatus.COMPLETED - ) - ) - .order_by(Order.created_at.desc()) - ) - return result.scalars().all() - -async def get_top_selling_items(db: AsyncSession, date: str, limit: int = 5) -> List[Dict]: - """Get top selling items for a specific date.""" - day_start = datetime.fromisoformat(date) - day_end = day_start.replace(hour=23, minute=59, second=59) - - result = await db.execute( - select( - MenuItem.name, - func.sum(OrderItem.quantity).label('total_quantity'), - func.sum(OrderItem.quantity * OrderItem.unit_price).label('total_revenue') - ) - .join(OrderItem, MenuItem.id == OrderItem.menu_item_id) - .join(Order, OrderItem.order_id == Order.id) - .where( - and_( - Order.created_at >= day_start, - Order.created_at <= day_end, - Order.status == OrderStatus.COMPLETED - ) - ) - .group_by(MenuItem.id, MenuItem.name) - .order_by(func.sum(OrderItem.quantity).desc()) - .limit(limit) - ) - - return [ - { - "item_name": row[0], - "quantity_sold": row[1], - "total_revenue": row[2] - } - for row in result.all() - ] - -async def get_daily_revenue(db: AsyncSession, date: str) -> float: - """Get total revenue for a specific date.""" - day_start = datetime.fromisoformat(date) - day_end = day_start.replace(hour=23, minute=59, second=59) - - result = await db.execute( - select(func.sum(Payment.amount)) - .join(Order, Payment.order_id == Order.id) - .where( - and_( - Payment.created_at >= day_start, - Payment.created_at <= day_end, - Payment.status == PaymentStatus.COMPLETED - ) - ) - ) - - total = result.scalar_one_or_none() - return float(total) if total is not None else 0.0 diff --git a/pos_backend/app/db/database.py b/pos_backend/app/db/database.py deleted file mode 100644 index 47f88efc12c0907d35fbe1f943882ffe7dca728d..0000000000000000000000000000000000000000 --- a/pos_backend/app/db/database.py +++ /dev/null @@ -1,83 +0,0 @@ -from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker -from sqlalchemy.orm import DeclarativeBase -from sqlalchemy import text -from ..core.config import settings -import logging -import ssl -import platform -import asyncio - -logger = logging.getLogger(__name__) - -def get_ssl_context(): - """Create an SSL context for database connection.""" - ssl_context = ssl.create_default_context() - ssl_context.check_hostname = False - ssl_context.verify_mode = ssl.CERT_NONE - return ssl_context - -# Configure Windows-specific event loop policy -if platform.system() == 'Windows': - asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) - -# Create async engine with connection pooling -engine = create_async_engine( - settings.DATABASE_URL, - echo=True, - pool_pre_ping=True, - pool_size=20, - max_overflow=10, - pool_timeout=30, - connect_args={ - "ssl": get_ssl_context(), - "server_settings": { - "application_name": "pos_backend", - "statement_timeout": "60000", # 60 seconds - } - } -) - -# Create async session maker with pooling configuration -async_session_maker = async_sessionmaker( - engine, - class_=AsyncSession, - expire_on_commit=False, - autocommit=False, - autoflush=False -) - -class Base(DeclarativeBase): - pass - -async def verify_connection(): - try: - async with engine.connect() as conn: - await conn.execute(text("SELECT 1")) - logger.info("Database connection verified successfully") - return True - except Exception as e: - logger.error(f"Database connection failed: {str(e)}") - raise - -async def get_db(): - async with async_session_maker() as session: - try: - await verify_connection() - yield session - await session.commit() - except Exception as e: - logger.error(f"Database session error: {str(e)}") - await session.rollback() - raise - finally: - await session.close() - -async def init_db(): - try: - await verify_connection() - async with engine.begin() as conn: - await conn.run_sync(Base.metadata.create_all) - logger.info("Database initialized successfully") - except Exception as e: - logger.error(f"Database initialization failed: {str(e)}") - raise diff --git a/pos_backend/app/db/models.py b/pos_backend/app/db/models.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/pos_backend/app/main.py b/pos_backend/app/main.py deleted file mode 100644 index 23d3c977ce04d47e2da1d68a2ddb6c9c2710102a..0000000000000000000000000000000000000000 --- a/pos_backend/app/main.py +++ /dev/null @@ -1,72 +0,0 @@ -import os -import sys -from pathlib import Path -from fastapi import FastAPI, HTTPException -from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import JSONResponse -from .core.config import settings -from .api.api_v1.api import api_router -from .db.database import init_db -import logging -import asyncio - -# Set up Python path -BASE_DIR = Path(__file__).resolve().parent.parent -sys.path.append(str(BASE_DIR)) - -# Configure logging -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) - -def create_app() -> FastAPI: - app = FastAPI( - title=settings.PROJECT_NAME, - openapi_url=f"{settings.API_V1_STR}/openapi.json" - ) - - # Configure CORS - app.add_middleware( - CORSMiddleware, - allow_origins=["*"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], - ) - - # Include API router - app.include_router(api_router, prefix=settings.API_V1_STR) - - @app.exception_handler(HTTPException) - async def http_exception_handler(request, exc): - return JSONResponse( - status_code=exc.status_code, - content={"detail": exc.detail} - ) - - @app.get("/") - async def root(): - return {"message": "POS Backend API", "version": "1.0.0"} - - @app.on_event("startup") - async def startup_event(): - try: - await init_db() - logger.info("Database initialized successfully") - except Exception as e: - logger.error(f"Failed to initialize database: {e}") - raise - - return app - -app = create_app() - -if __name__ == "__main__": - import uvicorn - - uvicorn.run( - "app.main:app", - host="0.0.0.0", - port=8000, - reload=True, - log_level="info" - ) diff --git a/pos_backend/app/models/__pycache__/auth.cpython-312.pyc b/pos_backend/app/models/__pycache__/auth.cpython-312.pyc deleted file mode 100644 index 30832a81622e9d857a14d28efe48e3aae4643f82..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/models/__pycache__/auth.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/models/__pycache__/database.cpython-312.pyc b/pos_backend/app/models/__pycache__/database.cpython-312.pyc deleted file mode 100644 index 65245047f7313539e3d825b695ca687378abea0e..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/models/__pycache__/database.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/models/__pycache__/menu.cpython-312.pyc b/pos_backend/app/models/__pycache__/menu.cpython-312.pyc deleted file mode 100644 index 31a78a2de4c6bfb7f5cfec06ddc0956fdd55db0f..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/models/__pycache__/menu.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/models/__pycache__/orders.cpython-312.pyc b/pos_backend/app/models/__pycache__/orders.cpython-312.pyc deleted file mode 100644 index a75d2bd70de990f539b500f438067fd89deb9bc3..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/models/__pycache__/orders.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/models/__pycache__/payment.cpython-312.pyc b/pos_backend/app/models/__pycache__/payment.cpython-312.pyc deleted file mode 100644 index fb98b1a7ac2422d1a213b6520108448bcc6650c1..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/models/__pycache__/payment.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/models/__pycache__/reports.cpython-312.pyc b/pos_backend/app/models/__pycache__/reports.cpython-312.pyc deleted file mode 100644 index 74375853f16ad9e876156d1915522f2bff71cdbc..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/models/__pycache__/reports.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/models/auth.py b/pos_backend/app/models/auth.py deleted file mode 100644 index a6dd2a2db07818effd24f0d4dca53edc6906b664..0000000000000000000000000000000000000000 --- a/pos_backend/app/models/auth.py +++ /dev/null @@ -1,17 +0,0 @@ -from pydantic import BaseModel, EmailStr, Field -from typing import Optional - -class LoginRequest(BaseModel): - email: EmailStr - password: str = Field(..., min_length=6) - -class LoginResponse(BaseModel): - access_token: str - token_type: str - user: 'UserProfile' - -class UserProfile(BaseModel): - id: Optional[int] = None - email: EmailStr - full_name: str - role: str \ No newline at end of file diff --git a/pos_backend/app/models/database.py b/pos_backend/app/models/database.py deleted file mode 100644 index cacc200322cb5c66dbfab40763c08a2df3f24246..0000000000000000000000000000000000000000 --- a/pos_backend/app/models/database.py +++ /dev/null @@ -1,72 +0,0 @@ -from sqlalchemy import Column, Integer, String, Float, ForeignKey, DateTime, Boolean, JSON, Enum -from sqlalchemy.orm import relationship -from datetime import datetime -from .menu import CategoryType -from ..db.database import Base - -class User(Base): - __tablename__ = "users" - - id = Column(Integer, primary_key=True, index=True) - email = Column(String, unique=True, index=True) - full_name = Column(String) - hashed_password = Column(String) - role = Column(String) - created_at = Column(DateTime, default=datetime.utcnow) - -class Category(Base): - __tablename__ = "categories" - - id = Column(Integer, primary_key=True, index=True) - name = Column(String, index=True) - type = Column(Enum(CategoryType)) - description = Column(String, nullable=True) - items = relationship("MenuItem", back_populates="category") - -class MenuItem(Base): - __tablename__ = "menu_items" - - id = Column(Integer, primary_key=True, index=True) - name = Column(String, index=True) - description = Column(String, nullable=True) - price = Column(Float) - category_id = Column(Integer, ForeignKey("categories.id")) - image_url = Column(String, nullable=True) - is_available = Column(Boolean, default=True) - allergens = Column(JSON, nullable=True) - preparation_time = Column(Integer, nullable=True) - category = relationship("Category", back_populates="items") - -class Order(Base): - __tablename__ = "orders" - - id = Column(Integer, primary_key=True, index=True) - user_id = Column(Integer, ForeignKey("users.id")) - total_amount = Column(Float) - status = Column(String) - created_at = Column(DateTime, default=datetime.utcnow) - items = relationship("OrderItem", back_populates="order") - payment = relationship("Payment", back_populates="order") - -class OrderItem(Base): - __tablename__ = "order_items" - - id = Column(Integer, primary_key=True, index=True) - order_id = Column(Integer, ForeignKey("orders.id")) - menu_item_id = Column(Integer, ForeignKey("menu_items.id")) - quantity = Column(Integer) - unit_price = Column(Float) - order = relationship("Order", back_populates="items") - menu_item = relationship("MenuItem") - -class Payment(Base): - __tablename__ = "payments" - - id = Column(Integer, primary_key=True, index=True) - order_id = Column(Integer, ForeignKey("orders.id")) - amount = Column(Float) - method = Column(String) - status = Column(String) - transaction_id = Column(String, nullable=True) - created_at = Column(DateTime, default=datetime.utcnow) - order = relationship("Order", back_populates="payment") diff --git a/pos_backend/app/models/menu.py b/pos_backend/app/models/menu.py deleted file mode 100644 index 9bbd7569be4a2c9f757af8e34c0786ed78cd14ab..0000000000000000000000000000000000000000 --- a/pos_backend/app/models/menu.py +++ /dev/null @@ -1,32 +0,0 @@ -from pydantic import BaseModel, Field -from typing import Optional, List -from decimal import Decimal -from enum import Enum - -class CategoryType(str, Enum): - SOUPS = "soups" # For Egusi, Efo riro, Ogbono, etc. - SWALLOW = "swallow" # For Pounded yam, Amala, Eba, etc. - RICE_DISHES = "rice_dishes" # For Jollof rice, Fried rice, Native rice - PROTEINS = "proteins" # For Suya, Asun, Grilled fish, etc. - SMALL_CHOPS = "small_chops" # For Puff puff, Samosa, Spring rolls - PEPPER_SOUP = "pepper_soup" # For various pepper soup varieties - SIDES = "sides" # For Plantains, Moin moin, etc. - DRINKS = "drinks" # For Nigerian drinks and beverages - -class Category(BaseModel): - id: Optional[int] = None - name: str - type: CategoryType - description: Optional[str] = None - -class MenuItem(BaseModel): - id: Optional[int] = None - name: str - description: Optional[str] = None - price: Decimal = Field(..., gt=0) - category_id: int - image_url: Optional[str] = None - is_available: bool = True - allergens: Optional[List[str]] = None - preparation_time: Optional[int] = None # in minutes - calories: Optional[int] = None \ No newline at end of file diff --git a/pos_backend/app/models/orders.py b/pos_backend/app/models/orders.py deleted file mode 100644 index 4300c6bea97e80a6352357bd9c85ab7d477e7afb..0000000000000000000000000000000000000000 --- a/pos_backend/app/models/orders.py +++ /dev/null @@ -1,37 +0,0 @@ -from pydantic import BaseModel -from typing import List, Optional -from datetime import datetime -from enum import Enum - -class OrderStatus(str, Enum): - PENDING = "pending" - PREPARING = "preparing" - READY = "ready" - DELIVERED = "delivered" - CANCELLED = "cancelled" - -class OrderItem(BaseModel): - menu_item_id: int - quantity: int - unit_price: float - notes: Optional[str] = None - -class Order(BaseModel): - id: Optional[int] = None - customer_id: int - items: List[OrderItem] - total_amount: float - status: OrderStatus - created_at: datetime - updated_at: Optional[datetime] = None - -class OrderDetails(Order): - payment_status: str - server_name: str - table_number: Optional[int] = None - -class OrderStats(BaseModel): - total_orders: int - total_revenue: float - average_order_value: float - orders_by_status: dict[OrderStatus, int] \ No newline at end of file diff --git a/pos_backend/app/models/payment.py b/pos_backend/app/models/payment.py deleted file mode 100644 index b6cf6d4d873103408a4376ba8239f594bf354d66..0000000000000000000000000000000000000000 --- a/pos_backend/app/models/payment.py +++ /dev/null @@ -1,24 +0,0 @@ -from enum import Enum -from pydantic import BaseModel, Field -from datetime import datetime -from typing import Optional - -class PaymentMethod(str, Enum): - CASH = "cash" - CARD = "card" - -class PaymentStatus(str, Enum): - PENDING = "pending" - PROCESSING = "processing" - COMPLETED = "completed" - FAILED = "failed" - -class Payment(BaseModel): - id: Optional[int] = None - order_id: int - amount: float = Field(..., gt=0) - method: PaymentMethod - status: PaymentStatus = PaymentStatus.PENDING - transaction_id: Optional[str] = None - created_at: datetime = Field(default_factory=datetime.utcnow) - updated_at: Optional[datetime] = None diff --git a/pos_backend/app/models/payments.py b/pos_backend/app/models/payments.py deleted file mode 100644 index b1e900a436f00aca198381933e9f913218f34a18..0000000000000000000000000000000000000000 --- a/pos_backend/app/models/payments.py +++ /dev/null @@ -1,42 +0,0 @@ -from pydantic import BaseModel -from typing import Optional -from datetime import datetime -from decimal import Decimal -from enum import Enum - -class PaymentMethod(str, Enum): - CASH = "cash" - CREDIT_CARD = "credit_card" - DEBIT_CARD = "debit_card" - MOBILE_PAYMENT = "mobile_payment" - -class PaymentStatus(str, Enum): - PENDING = "pending" - PROCESSING = "processing" - COMPLETED = "completed" - FAILED = "failed" - REFUNDED = "refunded" - -class PaymentSession(BaseModel): - id: str - order_id: int - amount: Decimal - payment_method: PaymentMethod - status: PaymentStatus - created_at: datetime - -class PaymentVerification(BaseModel): - payment_id: str - verification_code: str - status: PaymentStatus - message: Optional[str] = None - -class Transaction(BaseModel): - id: str - order_id: int - amount: Decimal - payment_method: PaymentMethod - status: PaymentStatus - created_at: datetime - updated_at: Optional[datetime] = None - reference_id: Optional[str] = None \ No newline at end of file diff --git a/pos_backend/app/models/reports.py b/pos_backend/app/models/reports.py deleted file mode 100644 index dc40e7821132175b1b0fb98cbdb2b55c762eb19c..0000000000000000000000000000000000000000 --- a/pos_backend/app/models/reports.py +++ /dev/null @@ -1,50 +0,0 @@ -from pydantic import BaseModel -from typing import Dict, List -from datetime import datetime -from decimal import Decimal - -class TopSellingItem(BaseModel): - item_name: str - quantity_sold: int - total_revenue: float - -class DailyReport(BaseModel): - date: str - total_sales: int - total_revenue: float - top_selling_items: List[TopSellingItem] - -class DailyBreakdown(BaseModel): - date: str - revenue: float - -class WeeklyReport(BaseModel): - period: str - total_sales: int - daily_breakdown: List[DailyBreakdown] - -# Future report models -class SalesReport(BaseModel): - total_sales: Decimal - sales_by_category: Dict[str, Decimal] - sales_by_item: Dict[str, Decimal] - sales_by_hour: Dict[int, Decimal] - average_order_value: Decimal - peak_hours: List[int] - period_start: datetime - period_end: datetime - -class InventoryReport(BaseModel): - items_in_stock: Dict[str, int] - low_stock_items: List[str] - out_of_stock_items: List[str] - total_inventory_value: Decimal - last_updated: datetime - -class PerformanceMetrics(BaseModel): - order_fulfillment_time: Dict[str, float] # avg time in minutes by order type - server_performance: Dict[str, Dict[str, float]] # metrics by server - customer_satisfaction: float - busy_periods: List[Dict[str, str]] - period_start: datetime - period_end: datetime \ No newline at end of file diff --git a/pos_backend/app/routes/auth.py b/pos_backend/app/routes/auth.py deleted file mode 100644 index 44b5c93591737985c676f0e9b72858460e171bd1..0000000000000000000000000000000000000000 --- a/pos_backend/app/routes/auth.py +++ /dev/null @@ -1,24 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException -from fastapi.security import OAuth2PasswordRequestForm -from ..models.auth import LoginRequest, LoginResponse, UserProfile -from ..core.auth import get_current_user -from ..services.auth_service import authenticate_user, create_access_token - -router = APIRouter(prefix="/api/auth", tags=["auth"]) - -@router.post("/login", response_model=LoginResponse) -async def login(form_data: OAuth2PasswordRequestForm = Depends()): - user = await authenticate_user(form_data.username, form_data.password) - if not user: - raise HTTPException(status_code=401, detail="Incorrect email or password") - access_token = create_access_token(data={"sub": user.email}) - return LoginResponse(access_token=access_token) - -@router.post("/logout") -async def logout(current_user = Depends(get_current_user)): - # TODO: Implement token blacklisting or session invalidation - return {"message": "Successfully logged out"} - -@router.get("/profile", response_model=UserProfile) -async def get_profile(current_user = Depends(get_current_user)): - return current_user \ No newline at end of file diff --git a/pos_backend/app/routes/menu.py b/pos_backend/app/routes/menu.py deleted file mode 100644 index 78baef67814179a39356b93ba874f04ee25911b7..0000000000000000000000000000000000000000 --- a/pos_backend/app/routes/menu.py +++ /dev/null @@ -1,52 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException -from typing import List -from ..models.menu import MenuItem, Category -from ..core.auth import get_current_user -from ..services.menu_service import MenuService - -router = APIRouter(prefix="/api/menu", tags=["menu"]) - -@router.get("", response_model=List[MenuItem]) -async def get_menu_items( - current_user = Depends(get_current_user), - menu_service: MenuService = Depends() -): - return await menu_service.get_menu_items() - -@router.post("", response_model=MenuItem) -async def create_menu_item( - item: MenuItem, - current_user = Depends(get_current_user), - menu_service: MenuService = Depends() -): - return await menu_service.create_menu_item(item) - -@router.put("/{item_id}", response_model=MenuItem) -async def update_menu_item( - item_id: int, - item: MenuItem, - current_user = Depends(get_current_user), - menu_service: MenuService = Depends() -): - updated_item = await menu_service.update_menu_item(item_id, item) - if not updated_item: - raise HTTPException(status_code=404, detail="Menu item not found") - return updated_item - -@router.delete("/{item_id}") -async def delete_menu_item( - item_id: int, - current_user = Depends(get_current_user), - menu_service: MenuService = Depends() -): - success = await menu_service.delete_menu_item(item_id) - if not success: - raise HTTPException(status_code=404, detail="Menu item not found") - return {"message": "Menu item deleted successfully"} - -@router.get("/categories", response_model=List[Category]) -async def get_categories( - current_user = Depends(get_current_user), - menu_service: MenuService = Depends() -): - return await menu_service.get_categories() \ No newline at end of file diff --git a/pos_backend/app/routes/orders.py b/pos_backend/app/routes/orders.py deleted file mode 100644 index 45ad5b1517c698d88cf08b5ae818f5860586cacb..0000000000000000000000000000000000000000 --- a/pos_backend/app/routes/orders.py +++ /dev/null @@ -1,63 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException -from typing import List -from ..models.orders import Order, OrderDetails, OrderStats -from ..core.auth import get_current_user -from ..services.order_service import OrderService - -router = APIRouter(prefix="/api/orders", tags=["orders"]) - -@router.get("", response_model=List[Order]) -async def get_orders( - current_user = Depends(get_current_user), - order_service: OrderService = Depends() -): - return await order_service.get_orders() - -@router.post("", response_model=Order) -async def create_order( - order: Order, - current_user = Depends(get_current_user), - order_service: OrderService = Depends() -): - return await order_service.create_order(order) - -@router.get("/{order_id}", response_model=OrderDetails) -async def get_order( - order_id: int, - current_user = Depends(get_current_user), - order_service: OrderService = Depends() -): - order = await order_service.get_order(order_id) - if not order: - raise HTTPException(status_code=404, detail="Order not found") - return order - -@router.put("/{order_id}", response_model=Order) -async def update_order( - order_id: int, - order: Order, - current_user = Depends(get_current_user), - order_service: OrderService = Depends() -): - updated_order = await order_service.update_order(order_id, order) - if not updated_order: - raise HTTPException(status_code=404, detail="Order not found") - return updated_order - -@router.delete("/{order_id}") -async def delete_order( - order_id: int, - current_user = Depends(get_current_user), - order_service: OrderService = Depends() -): - success = await order_service.delete_order(order_id) - if not success: - raise HTTPException(status_code=404, detail="Order not found") - return {"message": "Order deleted successfully"} - -@router.get("/stats", response_model=OrderStats) -async def get_order_stats( - current_user = Depends(get_current_user), - order_service: OrderService = Depends() -): - return await order_service.get_stats() \ No newline at end of file diff --git a/pos_backend/app/routes/payments.py b/pos_backend/app/routes/payments.py deleted file mode 100644 index 4ecc782f3f10b767db635e2f4f96746e22dd0457..0000000000000000000000000000000000000000 --- a/pos_backend/app/routes/payments.py +++ /dev/null @@ -1,33 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException -from typing import List -from ..models.payments import PaymentSession, PaymentVerification, Transaction -from ..core.auth import get_current_user -from ..services.payment_service import PaymentService - -router = APIRouter(prefix="/api/payments", tags=["payments"]) - -@router.post("/initiate", response_model=PaymentSession) -async def initiate_payment( - payment: PaymentSession, - current_user = Depends(get_current_user), - payment_service: PaymentService = Depends() -): - return await payment_service.initiate_payment(payment) - -@router.post("/verify", response_model=PaymentVerification) -async def verify_payment( - verification: PaymentVerification, - current_user = Depends(get_current_user), - payment_service: PaymentService = Depends() -): - result = await payment_service.verify_payment(verification) - if not result: - raise HTTPException(status_code=400, detail="Payment verification failed") - return result - -@router.get("/transactions", response_model=List[Transaction]) -async def get_transactions( - current_user = Depends(get_current_user), - payment_service: PaymentService = Depends() -): - return await payment_service.get_transactions() \ No newline at end of file diff --git a/pos_backend/app/routes/reports.py b/pos_backend/app/routes/reports.py deleted file mode 100644 index 703529ef984af8374a8c7a7dca382504912f39c8..0000000000000000000000000000000000000000 --- a/pos_backend/app/routes/reports.py +++ /dev/null @@ -1,27 +0,0 @@ -from fastapi import APIRouter, Depends -from ..models.reports import SalesReport, InventoryReport, PerformanceMetrics -from ..core.auth import get_current_user -from ..services.report_service import ReportService - -router = APIRouter(prefix="/api/reports", tags=["reports"]) - -@router.get("/sales", response_model=SalesReport) -async def get_sales_report( - current_user = Depends(get_current_user), - report_service: ReportService = Depends() -): - return await report_service.get_sales_report() - -@router.get("/inventory", response_model=InventoryReport) -async def get_inventory_report( - current_user = Depends(get_current_user), - report_service: ReportService = Depends() -): - return await report_service.get_inventory_report() - -@router.get("/performance", response_model=PerformanceMetrics) -async def get_performance_metrics( - current_user = Depends(get_current_user), - report_service: ReportService = Depends() -): - return await report_service.get_performance_metrics() \ No newline at end of file diff --git a/pos_backend/app/services/__pycache__/auth_service.cpython-312.pyc b/pos_backend/app/services/__pycache__/auth_service.cpython-312.pyc deleted file mode 100644 index cfa5c2559834421fcdbe423fe427a80be7db928c..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/services/__pycache__/auth_service.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/services/__pycache__/menu_service.cpython-312.pyc b/pos_backend/app/services/__pycache__/menu_service.cpython-312.pyc deleted file mode 100644 index a3c2766685e0efd335e584afc9f24fd286f11366..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/services/__pycache__/menu_service.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/services/__pycache__/order_service.cpython-312.pyc b/pos_backend/app/services/__pycache__/order_service.cpython-312.pyc deleted file mode 100644 index 7875ba78fc153d43563c5649a8dabce944e13439..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/services/__pycache__/order_service.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/services/__pycache__/payment_service.cpython-312.pyc b/pos_backend/app/services/__pycache__/payment_service.cpython-312.pyc deleted file mode 100644 index 87efadc857b2f37a4ea57471272ee61797cd0074..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/services/__pycache__/payment_service.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/services/__pycache__/report_service.cpython-312.pyc b/pos_backend/app/services/__pycache__/report_service.cpython-312.pyc deleted file mode 100644 index a33d1135a81b263faf2670ba57635609a54693ed..0000000000000000000000000000000000000000 Binary files a/pos_backend/app/services/__pycache__/report_service.cpython-312.pyc and /dev/null differ diff --git a/pos_backend/app/services/auth_service.py b/pos_backend/app/services/auth_service.py deleted file mode 100644 index b8792ce596ec77f866d624c2dfd6863ad7e5fcb6..0000000000000000000000000000000000000000 --- a/pos_backend/app/services/auth_service.py +++ /dev/null @@ -1,123 +0,0 @@ -from datetime import datetime, timedelta -from typing import Optional -from fastapi import Depends, HTTPException, status -from fastapi.security import OAuth2PasswordBearer -from jose import JWTError, jwt -from passlib.context import CryptContext -from ..models.auth import UserProfile, LoginResponse -from ..core.config import settings -from ..db.crud import get_user_by_email - -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/auth/login") - -async def authenticate_user(email: str, password: str) -> Optional[UserProfile]: - """Authenticate a user and return their profile if credentials are valid.""" - user = await get_user_by_email(email) - if not user or not verify_password(password, user.hashed_password): - return None - return UserProfile( - id=user.id, - email=user.email, - full_name=user.full_name, - role=user.role - ) - -def verify_password(plain_password: str, hashed_password: str) -> bool: - """Verify a password against its hash.""" - return pwd_context.verify(plain_password, hashed_password) - -def get_password_hash(password: str) -> str: - """Generate password hash.""" - return pwd_context.hash(password) - -def create_access_token(data: dict) -> str: - """Create a JWT access token.""" - to_encode = data.copy() - expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) - to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode( - to_encode, - settings.SECRET_KEY, - algorithm=settings.ALGORITHM - ) - return encoded_jwt - -def create_refresh_token(data: dict) -> str: - """Create a JWT refresh token.""" - to_encode = data.copy() - expire = datetime.utcnow() + timedelta(days=settings.REFRESH_TOKEN_EXPIRE_DAYS) - to_encode.update({"exp": expire, "refresh": True}) - return jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM) - -async def refresh_access_token(refresh_token: str) -> LoginResponse: - """Create new access token using refresh token.""" - try: - payload = jwt.decode( - refresh_token, - settings.SECRET_KEY, - algorithms=[settings.ALGORITHM] - ) - if not payload.get("refresh"): - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Invalid refresh token" - ) - email: str = payload.get("sub") - if email is None: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Invalid refresh token" - ) - user = await get_user_by_email(email) - if not user: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="User not found" - ) - access_token = create_access_token({"sub": user.email}) - return LoginResponse( - access_token=access_token, - token_type="bearer", - user=UserProfile( - id=user.id, - email=user.email, - full_name=user.full_name, - role=user.role - ) - ) - except JWTError: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Invalid refresh token" - ) - -async def get_current_user(token: str = Depends(oauth2_scheme)) -> UserProfile: - """Get the current authenticated user from JWT token.""" - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - headers={"WWW-Authenticate": "Bearer"}, - ) - try: - payload = jwt.decode( - token, - settings.SECRET_KEY, - algorithms=[settings.ALGORITHM] - ) - email: str = payload.get("sub") - if email is None: - raise credentials_exception - except JWTError: - raise credentials_exception - - user = await get_user_by_email(email) - if user is None: - raise credentials_exception - - return UserProfile( - id=user.id, - email=user.email, - full_name=user.full_name, - role=user.role - ) \ No newline at end of file diff --git a/pos_backend/app/services/menu_service.py b/pos_backend/app/services/menu_service.py deleted file mode 100644 index 2d515177c2ca9b990ed8b145a6dda8daec9bf667..0000000000000000000000000000000000000000 --- a/pos_backend/app/services/menu_service.py +++ /dev/null @@ -1,137 +0,0 @@ -from typing import List, Optional -from fastapi import HTTPException, status, Depends -from sqlalchemy.ext.asyncio import AsyncSession -from app.models.menu import MenuItem, Category -from ..db.crud import ( - get_menu_items, - get_menu_item_by_id, - create_menu_item_db, - update_menu_item_db, - delete_menu_item_db, - get_categories_db -) -from ..db.database import get_db - -class MenuService: - def __init__(self, db: AsyncSession = Depends(get_db)): - self.db = db - - async def get_menu_items(self) -> List[MenuItem]: - """Get all menu items.""" - try: - menu_items = await get_menu_items(self.db) - if not menu_items: - return [] - return menu_items - except Exception as e: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=f"Failed to fetch menu items: {str(e)}" - ) - - async def create_menu_item(self, item: MenuItem) -> MenuItem: - """Create a new menu item.""" - await self.validate_menu_item(item) - try: - return await create_menu_item_db(self.db, item) - except Exception as e: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=f"Failed to create menu item: {str(e)}" - ) - - async def update_menu_item(self, item_id: int, item: MenuItem) -> Optional[MenuItem]: - """Update an existing menu item.""" - await self.validate_menu_item(item) - existing_item = await get_menu_item_by_id(self.db, item_id) - if not existing_item: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Menu item not found" - ) - - try: - updated_item = await update_menu_item_db(self.db, item_id, item) - return updated_item - except Exception as e: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=f"Failed to update menu item: {str(e)}" - ) - - async def delete_menu_item(self, item_id: int) -> bool: - """Delete a menu item.""" - existing_item = await get_menu_item_by_id(self.db, item_id) - if not existing_item: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Menu item not found" - ) - - try: - success = await delete_menu_item_db(self.db, item_id) - return success - except Exception as e: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=f"Failed to delete menu item: {str(e)}" - ) - - async def get_categories(self) -> List[Category]: - """Get all menu categories. - - Returns: - List[Category]: List of all available categories - - Raises: - HTTPException: If there's a database error - """ - try: - categories = await get_categories_db(self.db) - if not categories: - return [] - return categories - except Exception as e: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=f"Failed to fetch categories: {str(e)}" - ) - - async def validate_menu_item(self, item: MenuItem) -> None: - """Validate menu item data. - - Args: - item (MenuItem): The menu item to validate - - Raises: - HTTPException: If validation fails - """ - if not item: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Menu item cannot be null" - ) - - if item.price <= 0: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Price must be greater than zero" - ) - - if not item.name.strip(): - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Item name cannot be empty" - ) - - if not item.category_id: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Category ID is required" - ) - - if item.description and len(item.description) > 500: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Description is too long (max 500 characters)" - ) \ No newline at end of file diff --git a/pos_backend/app/services/order_service.py b/pos_backend/app/services/order_service.py deleted file mode 100644 index dfea5bbac60ac435b1f6e0681d0fd0888c51b7b4..0000000000000000000000000000000000000000 --- a/pos_backend/app/services/order_service.py +++ /dev/null @@ -1,53 +0,0 @@ -from typing import List, Optional -from fastapi import HTTPException, status, Depends -from sqlalchemy.ext.asyncio import AsyncSession -from app.models.orders import Order, OrderItem, OrderStatus -from ..db.crud import ( - create_order_db, - get_order_by_id, - update_order_status, - get_orders_by_status, - get_orders_by_date_range -) -from ..db.database import get_db - -class OrderService: - def __init__(self, db: AsyncSession = Depends(get_db)): - self.db = db - - async def create_order(self, order: Order) -> Order: - """Create a new order.""" - if not order.items: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Order must contain items" - ) - return await create_order_db(self.db, order) - - async def get_order(self, order_id: int) -> Optional[Order]: - """Get order by ID.""" - order = await get_order_by_id(self.db, order_id) - if not order: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Order not found" - ) - return order - - async def update_status(self, order_id: int, new_status: OrderStatus) -> Order: - """Update order status.""" - order = await get_order_by_id(self.db, order_id) - if not order: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Order not found" - ) - return await update_order_status(self.db, order_id, new_status) - - async def get_orders_by_status(self, status: OrderStatus) -> List[Order]: - """Get orders by status.""" - return await get_orders_by_status(self.db, status) - - async def get_daily_orders(self, date: str) -> List[Order]: - """Get orders for a specific date.""" - return await get_orders_by_date_range(self.db, date, date) diff --git a/pos_backend/app/services/payment_service.py b/pos_backend/app/services/payment_service.py deleted file mode 100644 index d5be68d51a6c8d2e1614b584de5907a5c04e02a4..0000000000000000000000000000000000000000 --- a/pos_backend/app/services/payment_service.py +++ /dev/null @@ -1,67 +0,0 @@ -from typing import Optional -from fastapi import HTTPException, status, Depends -from sqlalchemy.ext.asyncio import AsyncSession -from ..models.payment import Payment, PaymentMethod, PaymentStatus -from ..db.crud import create_payment_db, get_payment_by_id, update_payment_status -from ..db.database import get_db - -class PaymentService: - def __init__(self, db: AsyncSession = Depends(get_db)): - self.db = db - - async def process_payment(self, payment: Payment) -> Payment: - """Process a new payment.""" - if payment.amount <= 0: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Payment amount must be greater than zero" - ) - - try: - # Process payment based on method - if payment.method == PaymentMethod.CASH: - return await self._process_cash_payment(payment) - elif payment.method == PaymentMethod.CARD: - return await self._process_card_payment(payment) - else: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Unsupported payment method" - ) - except Exception as e: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail=f"Payment processing failed: {str(e)}" - ) - - async def _process_cash_payment(self, payment: Payment) -> Payment: - """Handle cash payment.""" - payment.status = PaymentStatus.COMPLETED - return await create_payment_db(self.db, payment) - - async def _process_card_payment(self, payment: Payment) -> Payment: - """Handle card payment.""" - # Add card payment processing logic here - payment.status = PaymentStatus.PROCESSING - created_payment = await create_payment_db(self.db, payment) - return created_payment - - async def get_payment(self, payment_id: int) -> Optional[Payment]: - """Get payment by ID.""" - payment = await get_payment_by_id(self.db, payment_id) - if not payment: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Payment not found" - ) - return payment - - async def update_status(self, payment_id: int, new_status: PaymentStatus) -> Payment: - """Update payment status.""" - payment = await get_payment_by_id(self.db, payment_id) - if not payment: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Payment not found" - ) - return await update_payment_status(self.db, payment_id, new_status) diff --git a/pos_backend/app/services/report_service.py b/pos_backend/app/services/report_service.py deleted file mode 100644 index ee2acb482de92c30ad2efa9f07c6eaa664b9e28f..0000000000000000000000000000000000000000 --- a/pos_backend/app/services/report_service.py +++ /dev/null @@ -1,57 +0,0 @@ -from typing import Dict, List -from datetime import datetime, timedelta -from fastapi import Depends -from sqlalchemy.ext.asyncio import AsyncSession -from ..db.crud import ( - get_sales_by_date_range, - get_top_selling_items, - get_daily_revenue -) -from ..db.database import get_db - -class ReportService: - def __init__(self, db: AsyncSession = Depends(get_db)): - self.db = db - - async def generate_daily_report(self, date: str) -> Dict: - """Generate daily sales report.""" - sales = await get_sales_by_date_range(self.db, date, date) - revenue = await get_daily_revenue(self.db, date) - top_items = await get_top_selling_items(self.db, date, limit=5) - - return { - "date": date, - "total_sales": len(sales), - "total_revenue": revenue, - "top_selling_items": top_items - } - - async def generate_weekly_report(self, end_date: str = None) -> Dict: - """Generate weekly sales report.""" - if not end_date: - end_date = datetime.now().date().isoformat() - start_date = (datetime.fromisoformat(end_date) - timedelta(days=7)).isoformat() - - sales = await get_sales_by_date_range(self.db, start_date, end_date) - return { - "period": f"{start_date} to {end_date}", - "total_sales": len(sales), - "daily_breakdown": await self._get_daily_breakdown(start_date, end_date) - } - - async def _get_daily_breakdown(self, start_date: str, end_date: str) -> List[Dict]: - """Get daily sales breakdown.""" - current = datetime.fromisoformat(start_date) - end = datetime.fromisoformat(end_date) - breakdown = [] - - while current <= end: - date_str = current.date().isoformat() - revenue = await get_daily_revenue(self.db, date_str) - breakdown.append({ - "date": date_str, - "revenue": revenue - }) - current += timedelta(days=1) - - return breakdown diff --git a/pos_backend/app/utils/jwt.py b/pos_backend/app/utils/jwt.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/pos_backend/direct_test.py b/pos_backend/direct_test.py deleted file mode 100644 index 1f5c5a28490cf3c75ef78f09ee25ae0ecb540442..0000000000000000000000000000000000000000 --- a/pos_backend/direct_test.py +++ /dev/null @@ -1,57 +0,0 @@ -import asyncio -import asyncpg -import ssl -import logging -import sys -from datetime import datetime - -# Configure logging to both file and console -log_filename = f"db_connection_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log" -logging.basicConfig( - level=logging.DEBUG, - format='%(asctime)s - %(levelname)s - %(message)s', - handlers=[ - logging.FileHandler(log_filename), - logging.StreamHandler(sys.stdout) - ] -) -logger = logging.getLogger(__name__) - -async def test_direct_connection(): - logger.info("Starting database connection test") - ssl_context = ssl.create_default_context() - ssl_context.check_hostname = False - ssl_context.verify_mode = ssl.CERT_NONE - - try: - logger.info("Creating SSL context and attempting database connection...") - conn = await asyncpg.connect( - user='postgres', - password='Lovyelias5584.', - host='juycnkjuzylnbruwaqmp.supabase.co', - port=5432, - database='postgres', - ssl=ssl_context, - timeout=60.0 - ) - logger.info("Successfully connected to database!") - - version = await conn.fetchval('SELECT version()') - logger.info(f"Database version: {version}") - - await conn.close() - logger.info("Connection closed successfully") - - except Exception as e: - logger.error(f"Error connecting to database: {str(e)}", exc_info=True) - raise - finally: - logger.info("Test completed") - -if __name__ == "__main__": - try: - logger.info("Starting connection test script") - asyncio.run(test_direct_connection()) - except Exception as e: - logger.error("Fatal error in main", exc_info=True) - sys.exit(1) \ No newline at end of file diff --git a/pos_backend/main.py b/pos_backend/main.py deleted file mode 100644 index 297e42b3444d4827f4cfa072562a029caed557f3..0000000000000000000000000000000000000000 --- a/pos_backend/main.py +++ /dev/null @@ -1,71 +0,0 @@ -import asyncio -import platform -from fastapi import FastAPI, HTTPException -from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import JSONResponse -from app.core.config import settings -from app.api.api_v1.api import api_router -from app.db.database import init_db -import logging -import sys - -# Configure Windows-specific event loop policy -if platform.system() == 'Windows': - asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) - -# Configure detailed logging -logging.basicConfig( - level=logging.DEBUG, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', - stream=sys.stdout -) -logger = logging.getLogger(__name__) - -app = FastAPI( - title=settings.PROJECT_NAME, - openapi_url=f"{settings.API_V1_STR}/openapi.json" -) - -# Configure CORS -app.add_middleware( - CORSMiddleware, - allow_origins=["*"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"] -) - -# Include API router -app.include_router(api_router, prefix=settings.API_V1_STR) - -@app.exception_handler(HTTPException) -async def http_exception_handler(request, exc): - return JSONResponse( - status_code=exc.status_code, - content={"detail": exc.detail} - ) - -@app.get("/") -async def root(): - return {"message": "POS Backend API", "version": "1.0.0"} - -@app.on_event("startup") -async def startup_event(): - try: - logger.info("Starting application initialization...") - await init_db() - logger.info("Database initialized successfully") - except Exception as e: - logger.error(f"Failed to initialize database: {str(e)}", exc_info=True) - raise - -if __name__ == "__main__": - import uvicorn - logger.info("Starting application with Windows-compatible event loop...") - uvicorn.run( - "main:app", - host="0.0.0.0", - port=8000, - reload=True, - log_level="debug" - ) diff --git a/pos_backend/minimal_test.py b/pos_backend/minimal_test.py deleted file mode 100644 index a839f48eeff0538bf216d53cab0d4b9708c5923f..0000000000000000000000000000000000000000 --- a/pos_backend/minimal_test.py +++ /dev/null @@ -1,87 +0,0 @@ -import asyncio -import asyncpg -import ssl -import platform -import sys -import logging -from typing import Optional - -# Configure logging -logging.basicConfig( - level=logging.DEBUG, - format='%(asctime)s - %(levelname)s - %(message)s', - handlers=[logging.StreamHandler(sys.stdout)] -) -logger = logging.getLogger(__name__) - -async def get_ssl_context() -> ssl.SSLContext: - """Create an SSL context for database connection.""" - ssl_context = ssl.create_default_context() - ssl_context.check_hostname = False - ssl_context.verify_mode = ssl.CERT_NONE - return ssl_context - -async def test_connection() -> None: - """Test the database connection with detailed logging.""" - logger.info("Starting database connection test...") - - if platform.system() == 'Windows': - logger.info("Configuring Windows-specific event loop policy...") - asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) - - try: - ssl_context = await get_ssl_context() - logger.info("Attempting to establish database connection...") - - conn: Optional[asyncpg.Connection] = None - try: - conn = await asyncpg.connect( - user='postgres', - password='Lovyelias5584.', - database='postgres', - host='juycnkjuzylnbruwaqmp.supabase.co', - port=5432, - ssl=ssl_context, - command_timeout=30.0, - server_settings={'application_name': 'pos_backend_test'} - ) - - logger.info("Connection established successfully") - - # Test the connection with a simple query - result = await conn.fetchval('SELECT version()') - logger.info(f"Database version: {result}") - - # Test table access - tables = await conn.fetch(""" - SELECT table_name - FROM information_schema.tables - WHERE table_schema = 'public' - """) - logger.info("Available tables:") - for table in tables: - logger.info(f"- {table['table_name']}") - - except Exception as e: - logger.error(f"Database connection failed: {str(e)}", exc_info=True) - raise - finally: - if conn: - logger.info("Closing database connection...") - await conn.close() - logger.info("Database connection closed") - - except Exception as e: - logger.error(f"Test failed: {str(e)}", exc_info=True) - raise - else: - logger.info("Database connection test completed successfully") - -if __name__ == "__main__": - try: - asyncio.run(test_connection()) - except KeyboardInterrupt: - logger.info("Test interrupted by user") - except Exception as e: - logger.error("Fatal error occurred", exc_info=True) - sys.exit(1) \ No newline at end of file diff --git a/pos_backend/requirements.txt b/pos_backend/requirements.txt deleted file mode 100644 index 091e909289f8c6054826bc1635f05afcd03ff688..0000000000000000000000000000000000000000 --- a/pos_backend/requirements.txt +++ /dev/null @@ -1,13 +0,0 @@ -fastapi -uvicorn -python-jose[cryptography] -passlib[bcrypt] -pydantic -python-multipart -email-validator>=2.0.0 -pydantic[email]>=2.0.0 -python-dateutil -sqlalchemy -asyncpg -pydantic-settings -alembic \ No newline at end of file diff --git a/pos_backend/run.py b/pos_backend/run.py deleted file mode 100644 index fe912e579d12ef7f1b7d7d9e76a9c29888325c84..0000000000000000000000000000000000000000 --- a/pos_backend/run.py +++ /dev/null @@ -1,18 +0,0 @@ -import os -import sys -from pathlib import Path - -# Add the project root directory to Python path -root_dir = Path(__file__).resolve().parent -sys.path.append(str(root_dir)) - -import uvicorn - -if __name__ == "__main__": - uvicorn.run( - "app.main:app", - host="0.0.0.0", - port=8000, - reload=True, - log_level="info" - ) diff --git a/pos_backend/sync_test.py b/pos_backend/sync_test.py deleted file mode 100644 index 08c58804b12fff8534fe8d40abc7ecaf6a08e086..0000000000000000000000000000000000000000 --- a/pos_backend/sync_test.py +++ /dev/null @@ -1,56 +0,0 @@ -import psycopg2 -import sys -import os -from datetime import datetime - -# Get the absolute path to the log directory -log_dir = os.path.dirname(os.path.abspath(__file__)) -connection_log = os.path.join(log_dir, 'connection_log.txt') -error_log = os.path.join(log_dir, 'connection_error.txt') - -def write_log(message, is_error=False): - timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') - log_file = error_log if is_error else connection_log - with open(log_file, 'a') as f: - f.write(f"[{timestamp}] {message}\n") - # Also try printing to stderr for immediate feedback - print(message, file=sys.stderr) - -def test_sync_connection(): - write_log("Starting synchronous connection test") - try: - write_log("Attempting to connect to database...") - write_log(f"Using host: juycnkjuzylnbruwaqmp.supabase.co") - - conn = psycopg2.connect( - dbname="postgres", - user="postgres", - password="Lovyelias5584.", - host="juycnkjuzylnbruwaqmp.supabase.co", - port="5432", - sslmode="require", - connect_timeout=30 - ) - - write_log("Connected successfully!") - - # Test the connection - cur = conn.cursor() - cur.execute('SELECT version()') - version = cur.fetchone() - write_log(f"Database version: {version}") - - cur.close() - conn.close() - write_log("Connection closed successfully") - return True - - except Exception as e: - error_msg = f"Error connecting to database: {str(e)}" - write_log(error_msg, is_error=True) - return False - -if __name__ == "__main__": - success = test_sync_connection() - if not success: - sys.exit(1) \ No newline at end of file diff --git a/pos_backend/test_all.py b/pos_backend/test_all.py deleted file mode 100644 index a509fb4af71f3598a0975185cac5b35a25c2060a..0000000000000000000000000000000000000000 --- a/pos_backend/test_all.py +++ /dev/null @@ -1,125 +0,0 @@ -import socket -import ssl -import sys -import os -import asyncio -import asyncpg -import psycopg2 -from datetime import datetime - -# Configuration -HOST = "juycnkjuzylnbruwaqmp.supabase.co" -PORT = 5432 -USER = "postgres" -PASSWORD = "Lovyelias5584." -DATABASE = "postgres" - -def log_to_file(message): - timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') - with open('comprehensive_test.log', 'a') as f: - f.write(f"[{timestamp}] {message}\n") - -async def test_asyncpg(): - log_to_file("\n=== Testing asyncpg connection ===") - try: - ssl_context = ssl.create_default_context() - ssl_context.check_hostname = False - ssl_context.verify_mode = ssl.CERT_NONE - - log_to_file("Attempting asyncpg connection...") - conn = await asyncpg.connect( - user=USER, - password=PASSWORD, - database=DATABASE, - host=HOST, - port=PORT, - ssl=ssl_context - ) - log_to_file("asyncpg connection successful!") - await conn.close() - return True - except Exception as e: - log_to_file(f"asyncpg connection failed: {str(e)}") - return False - -def test_psycopg2(): - log_to_file("\n=== Testing psycopg2 connection ===") - try: - log_to_file("Attempting psycopg2 connection...") - conn = psycopg2.connect( - dbname=DATABASE, - user=USER, - password=PASSWORD, - host=HOST, - port=PORT, - sslmode='require' - ) - log_to_file("psycopg2 connection successful!") - conn.close() - return True - except Exception as e: - log_to_file(f"psycopg2 connection failed: {str(e)}") - return False - -def test_socket(): - log_to_file("\n=== Testing raw socket connection ===") - try: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.settimeout(10) - - # Try DNS resolution - try: - ip = socket.gethostbyname(HOST) - log_to_file(f"DNS resolution successful: {HOST} -> {ip}") - except socket.gaierror as e: - log_to_file(f"DNS resolution failed: {str(e)}") - return False - - # Try SSL connection - context = ssl.create_default_context() - context.check_hostname = False - context.verify_mode = ssl.CERT_NONE - - wrapped_socket = context.wrap_socket(sock) - log_to_file(f"Attempting connection to {HOST}:{PORT}...") - result = wrapped_socket.connect_ex((HOST, PORT)) - - if result == 0: - log_to_file(f"Socket connection successful!") - return True - else: - log_to_file(f"Socket connection failed with error code: {result}") - return False - except Exception as e: - log_to_file(f"Socket connection failed with error: {str(e)}") - return False - finally: - try: - sock.close() - except: - pass - -async def main(): - # Clear previous log - with open('comprehensive_test.log', 'w') as f: - f.write(f"=== Comprehensive Database Connection Test ===\n") - f.write(f"Started at: {datetime.now()}\n") - f.write(f"Python version: {sys.version}\n") - f.write(f"Platform: {sys.platform}\n\n") - - # Run tests - socket_result = test_socket() - psycopg2_result = test_psycopg2() - asyncpg_result = await test_asyncpg() - - # Log summary - log_to_file("\n=== Test Summary ===") - log_to_file(f"Socket test: {'PASSED' if socket_result else 'FAILED'}") - log_to_file(f"psycopg2 test: {'PASSED' if psycopg2_result else 'FAILED'}") - log_to_file(f"asyncpg test: {'PASSED' if asyncpg_result else 'FAILED'}") - - # Exit with status code - return 0 if (socket_result and psycopg2_result and asyncpg_result) else 1 - -if __name__ == "__main__": - sys.exit(asyncio.run(main())) \ No newline at end of file diff --git a/pos_backend/test_connection.py b/pos_backend/test_connection.py deleted file mode 100644 index 62cdd15208b9f72a79ffcf5fe9d3120c0ecf1df9..0000000000000000000000000000000000000000 --- a/pos_backend/test_connection.py +++ /dev/null @@ -1,44 +0,0 @@ -import asyncio -import logging -import sys -from app.db.database import verify_connection, init_db -from app.core.config import settings -import traceback - -# Configure logging to show all output -logging.basicConfig( - level=logging.DEBUG, - format='%(asctime)s - %(levelname)s - %(message)s', - handlers=[ - logging.StreamHandler(sys.stdout) - ] -) - -async def test_database(): - print("=== Database Connection Test ===") - print(f"Database URL: {settings.DATABASE_URL}") - try: - print("\nStep 1: Verifying basic connection...") - await verify_connection() - print("Basic connection successful!") - - print("\nStep 2: Initializing database...") - await init_db() - print("Database initialization successful!") - - print("\nAll tests passed successfully!") - except Exception as e: - print(f"\nError occurred: {str(e)}") - print("\nFull traceback:") - traceback.print_exc() - sys.exit(1) - -if __name__ == "__main__": - try: - asyncio.run(test_database()) - except KeyboardInterrupt: - print("\nTest interrupted by user") - except Exception as e: - print(f"\nFatal error: {str(e)}") - traceback.print_exc() - sys.exit(1) \ No newline at end of file diff --git a/pos_backend/test_db.py b/pos_backend/test_db.py deleted file mode 100644 index 6101b7418c1b3239ae6701b89e7429df22ff946a..0000000000000000000000000000000000000000 --- a/pos_backend/test_db.py +++ /dev/null @@ -1,17 +0,0 @@ -import psycopg2 -import traceback - -try: - print("Attempting database connection...") - conn = psycopg2.connect( - "dbname=postgres user=postgres password=Lovyelias5584. " - "host=juycnkjuzylnbruwaqmp.supabase.co port=5432 " - "sslmode=require" - ) - print("Connection successful!") - conn.close() -except Exception as e: - print(f"Connection failed!") - print(f"Error: {str(e)}") - print("\nTraceback:") - traceback.print_exc() \ No newline at end of file diff --git a/pos_backend/test_logging.py b/pos_backend/test_logging.py deleted file mode 100644 index 18ae016d5e112de25ad68199237ada2f2ad81adf..0000000000000000000000000000000000000000 --- a/pos_backend/test_logging.py +++ /dev/null @@ -1,10 +0,0 @@ -import sys -from datetime import datetime - -# Write directly to a file -with open('test_output.txt', 'w') as f: - f.write(f"Test run at {datetime.now()}\n") - f.write(f"Python version: {sys.version}\n") - f.write("If you can read this, file writing is working\n") - -print("Test completed - check test_output.txt") \ No newline at end of file diff --git a/pos_backend/test_network.py b/pos_backend/test_network.py deleted file mode 100644 index 80932438b3f2e68a3e3a3034d7389fbfa19e4cb2..0000000000000000000000000000000000000000 --- a/pos_backend/test_network.py +++ /dev/null @@ -1,49 +0,0 @@ -import socket -import ssl -import sys -import os -from urllib.parse import urlparse - -def test_network_connection(host, port): - try: - # Create a socket and set a timeout - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.settimeout(10) - - # Wrap the socket with SSL - context = ssl.create_default_context() - context.check_hostname = False - context.verify_mode = ssl.CERT_NONE - - wrapped_socket = context.wrap_socket(sock) - - # Try to connect - result = wrapped_socket.connect_ex((host, port)) - - if result == 0: - print(f"Successfully connected to {host}:{port}") - return True - else: - print(f"Failed to connect to {host}:{port}") - print(f"Error code: {result}") - return False - - except Exception as e: - print(f"Error: {str(e)}") - return False - finally: - try: - wrapped_socket.close() - except: - pass - -if __name__ == "__main__": - host = "juycnkjuzylnbruwaqmp.supabase.co" - port = 5432 - - print(f"Testing connection to {host}:{port}...") - print(f"Python version: {sys.version}") - print(f"Platform: {sys.platform}") - - success = test_network_connection(host, port) - sys.exit(0 if success else 1) \ No newline at end of file diff --git a/pos_backend/test_pooler.py b/pos_backend/test_pooler.py deleted file mode 100644 index c2343361b1745fbbf9b2f24505908f59b164f0e4..0000000000000000000000000000000000000000 --- a/pos_backend/test_pooler.py +++ /dev/null @@ -1,45 +0,0 @@ -import asyncio -import asyncpg -import ssl -import logging - -logging.basicConfig(level=logging.DEBUG) -logger = logging.getLogger(__name__) - -async def test_pooled_connection(): - try: - # Create SSL context - ssl_context = ssl.create_default_context() - ssl_context.check_hostname = False - ssl_context.verify_mode = ssl.CERT_NONE - - # Create connection pool - pool = await asyncpg.create_pool( - host='aws-0-eu-central-1.pooler.supabase.com', - port=5432, - user='postgres.juycnkjuzylnbruwaqmp', - password='Lovyelias5584.', - database='postgres', - ssl=ssl_context, - min_size=1, - max_size=10 - ) - - async with pool.acquire() as conn: - version = await conn.fetchval('SELECT version()') - print(f"Connected successfully! PostgreSQL version: {version}") - - # Test a simple query - result = await conn.fetchval('SELECT 1') - print(f"Test query result: {result}") - - await pool.close() - print("Connection pool closed successfully") - return True - - except Exception as e: - print(f"Connection error: {str(e)}") - return False - -if __name__ == "__main__": - asyncio.run(test_pooled_connection()) \ No newline at end of file diff --git a/pos_backend/tests/test_auth.py b/pos_backend/tests/test_auth.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/pos_backend/tests/test_orders.py b/pos_backend/tests/test_orders.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000