# ================================================================ # services/orders/app/main.py # ================================================================ """ Orders Service - FastAPI Application Customer orders and procurement planning service """ from fastapi import FastAPI, Request from sqlalchemy import text from app.core.config import settings from app.core.database import database_manager from app.api.orders import router as orders_router from app.api.customers import router as customers_router from app.api.order_operations import router as order_operations_router from app.api.procurement_operations import router as procurement_operations_router from app.services.procurement_scheduler_service import ProcurementSchedulerService from shared.service_base import StandardFastAPIService class OrdersService(StandardFastAPIService): """Orders Service with standardized setup""" expected_migration_version = "00001" async def on_startup(self, app): """Custom startup logic including migration verification""" await self.verify_migrations() await super().on_startup(app) async def verify_migrations(self): """Verify database schema matches the latest migrations.""" try: async with self.database_manager.get_session() as session: result = await session.execute(text("SELECT version_num FROM alembic_version")) version = result.scalar() if version != self.expected_migration_version: self.logger.error(f"Migration version mismatch: expected {self.expected_migration_version}, got {version}") raise RuntimeError(f"Migration version mismatch: expected {self.expected_migration_version}, got {version}") self.logger.info(f"Migration verification successful: {version}") except Exception as e: self.logger.error(f"Migration verification failed: {e}") raise def __init__(self): # Define expected database tables for health checks orders_expected_tables = [ 'customers', 'customer_contacts', 'customer_orders', 'order_items', 'order_status_history', 'procurement_plans', 'procurement_requirements' ] super().__init__( service_name="orders-service", app_name=settings.APP_NAME, description=settings.DESCRIPTION, version=settings.VERSION, api_prefix="", # Empty because RouteBuilder already includes /api/v1 database_manager=database_manager, expected_tables=orders_expected_tables ) async def on_startup(self, app: FastAPI): """Custom startup logic for orders service""" # Initialize procurement scheduler service scheduler_service = ProcurementSchedulerService(settings) await scheduler_service.start() self.logger.info("Procurement scheduler service started") # Store scheduler service in app state app.state.scheduler_service = scheduler_service async def on_shutdown(self, app: FastAPI): """Custom shutdown logic for orders service""" # Stop scheduler service if hasattr(app.state, 'scheduler_service'): await app.state.scheduler_service.stop() self.logger.info("Scheduler service stopped") def get_service_features(self): """Return orders-specific features""" return [ "customer_management", "order_processing", "procurement_planning", "order_tracking", "automated_scheduling" ] # Create service instance service = OrdersService() # Create FastAPI app with standardized setup app = service.create_app() # Setup standard endpoints service.setup_standard_endpoints() # Include routers - organized by ATOMIC and BUSINESS operations # ATOMIC: Direct CRUD operations service.add_router(orders_router) service.add_router(customers_router) # BUSINESS: Complex operations and workflows service.add_router(order_operations_router) service.add_router(procurement_operations_router) @app.post("/test/procurement-scheduler") async def test_procurement_scheduler(): """Test endpoint to manually trigger procurement scheduler""" try: if hasattr(app.state, 'scheduler_service'): scheduler_service = app.state.scheduler_service await scheduler_service.test_procurement_generation() return {"message": "Procurement scheduler test triggered successfully"} else: return {"error": "Scheduler service not available"} except Exception as e: service.logger.error("Error testing procurement scheduler", error=str(e)) return {"error": f"Failed to trigger scheduler test: {str(e)}"} @app.middleware("http") async def logging_middleware(request: Request, call_next): """Add request logging middleware""" import time start_time = time.time() response = await call_next(request) process_time = time.time() - start_time service.logger.info("HTTP request processed", method=request.method, url=str(request.url), status_code=response.status_code, process_time=round(process_time, 4)) return response if __name__ == "__main__": import uvicorn uvicorn.run( "main:app", host="0.0.0.0", port=8000, reload=settings.DEBUG )