Files
bakery-ia/services/sales/app/main.py
2025-12-05 20:07:01 +01:00

154 lines
5.3 KiB
Python

# services/sales/app/main.py
"""
Sales Service Main Application
"""
from fastapi import FastAPI
from sqlalchemy import text
from app.core.config import settings
from app.core.database import database_manager
from shared.service_base import StandardFastAPIService
# Import API routers
from app.api import sales_records, sales_operations, analytics, internal_demo, audit, batch
class SalesService(StandardFastAPIService):
"""Sales 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
sales_expected_tables = ['sales_data', 'sales_import_jobs']
super().__init__(
service_name="sales-service",
app_name="Bakery Sales Service",
description="Sales data management service for bakery operations",
version="1.0.0",
log_level=settings.LOG_LEVEL,
cors_origins=settings.CORS_ORIGINS,
api_prefix="", # Empty because RouteBuilder already includes /api/v1
database_manager=database_manager,
expected_tables=sales_expected_tables
)
async def on_startup(self, app: FastAPI):
"""Custom startup logic for sales service"""
# Register custom metrics
self.register_custom_metrics({
"sales_records_created_total": {
"type": "counter",
"description": "Total sales records created"
},
"sales_records_updated_total": {
"type": "counter",
"description": "Total sales records updated"
},
"sales_queries_total": {
"type": "counter",
"description": "Sales record queries"
},
"product_queries_total": {
"type": "counter",
"description": "Product catalog queries"
},
"import_jobs_total": {
"type": "counter",
"description": "Data import jobs"
},
"export_jobs_total": {
"type": "counter",
"description": "Data export jobs"
},
"sales_create_duration_seconds": {
"type": "histogram",
"description": "Sales record creation duration"
},
"sales_query_duration_seconds": {
"type": "histogram",
"description": "Sales query duration"
},
"import_processing_duration_seconds": {
"type": "histogram",
"description": "Import processing duration"
},
"export_generation_duration_seconds": {
"type": "histogram",
"description": "Export generation duration"
}
})
async def on_shutdown(self, app: FastAPI):
"""Custom shutdown logic for sales service"""
# Database cleanup is handled by the base class
pass
def get_service_features(self):
"""Return sales-specific features"""
return [
"sales_data_management",
"product_catalog",
"data_import_export",
"sales_analytics",
"performance_tracking"
]
def setup_custom_endpoints(self):
"""Setup custom endpoints for sales service"""
@self.app.get("/")
async def root():
"""Root endpoint"""
return {
"service": "Sales Service",
"version": "1.0.0",
"status": "running",
"endpoints": {
"health": "/health",
"docs": "/docs",
"sales": "/api/v1/sales",
"products": "/api/v1/products"
}
}
# Create service instance
service = SalesService()
# Create FastAPI app with standardized setup
app = service.create_app()
# Setup standard endpoints
service.setup_standard_endpoints()
# Setup custom endpoints
service.setup_custom_endpoints()
# Include routers
# IMPORTANT: Register audit router FIRST to avoid route matching conflicts
service.add_router(audit.router)
service.add_router(batch.router)
service.add_router(sales_records.router)
service.add_router(sales_operations.router)
service.add_router(analytics.router)
service.add_router(internal_demo.router)