Replace Flask admin with FastAPI app (api/app/) featuring: - Dashboard with stat cards, sync control, and history - Mappings CRUD for ARTICOLE_TERTI with CSV import/export - Article autocomplete from NOM_ARTICOLE - SKU pre-validation before import - Sync orchestration: read JSONs -> validate -> import -> log to SQLite - APScheduler for periodic sync from UI - File logging to logs/sync_comenzi_YYYYMMDD_HHMMSS.log - Oracle pool None guard (503 vs 500 on unavailable) Test suite: - test_app_basic.py: 30 tests (imports + routes) without Oracle - test_integration.py: 9 integration tests with Oracle Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
92 lines
2.9 KiB
Python
92 lines
2.9 KiB
Python
from contextlib import asynccontextmanager
|
|
from datetime import datetime
|
|
from fastapi import FastAPI
|
|
from fastapi.staticfiles import StaticFiles
|
|
from pathlib import Path
|
|
import logging
|
|
import os
|
|
|
|
from .config import settings
|
|
from .database import init_oracle, close_oracle, init_sqlite
|
|
|
|
# Configure logging with both stream and file handlers
|
|
_log_level = getattr(logging, settings.LOG_LEVEL.upper(), logging.INFO)
|
|
_log_format = '%(asctime)s | %(levelname)s | %(name)s | %(message)s'
|
|
_formatter = logging.Formatter(_log_format)
|
|
|
|
_stream_handler = logging.StreamHandler()
|
|
_stream_handler.setFormatter(_formatter)
|
|
|
|
_log_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'logs')
|
|
os.makedirs(_log_dir, exist_ok=True)
|
|
_log_filename = f"sync_comenzi_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
|
|
_file_handler = logging.FileHandler(os.path.join(_log_dir, _log_filename), encoding='utf-8')
|
|
_file_handler.setFormatter(_formatter)
|
|
|
|
_root_logger = logging.getLogger()
|
|
_root_logger.setLevel(_log_level)
|
|
_root_logger.addHandler(_stream_handler)
|
|
_root_logger.addHandler(_file_handler)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
"""Startup and shutdown events."""
|
|
logger.info("Starting GoMag Import Manager...")
|
|
|
|
# Initialize Oracle pool
|
|
try:
|
|
init_oracle()
|
|
except Exception as e:
|
|
logger.error(f"Oracle init failed: {e}")
|
|
# Allow app to start even without Oracle for development
|
|
|
|
# Initialize SQLite
|
|
init_sqlite()
|
|
|
|
# Initialize scheduler (restore saved config)
|
|
from .services import scheduler_service, sqlite_service
|
|
scheduler_service.init_scheduler()
|
|
try:
|
|
config = await sqlite_service.get_scheduler_config()
|
|
if config.get("enabled") == "True":
|
|
interval = int(config.get("interval_minutes", "5"))
|
|
scheduler_service.start_scheduler(interval)
|
|
except Exception:
|
|
pass
|
|
|
|
logger.info("GoMag Import Manager started")
|
|
yield
|
|
|
|
# Shutdown
|
|
scheduler_service.shutdown_scheduler()
|
|
close_oracle()
|
|
logger.info("GoMag Import Manager stopped")
|
|
|
|
app = FastAPI(
|
|
title="GoMag Import Manager",
|
|
description="Import comenzi web GoMag → ROA Oracle",
|
|
version="1.0.0",
|
|
lifespan=lifespan
|
|
)
|
|
|
|
# Static files and templates
|
|
static_dir = Path(__file__).parent / "static"
|
|
templates_dir = Path(__file__).parent / "templates"
|
|
static_dir.mkdir(parents=True, exist_ok=True)
|
|
(static_dir / "css").mkdir(exist_ok=True)
|
|
(static_dir / "js").mkdir(exist_ok=True)
|
|
templates_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
|
|
|
|
# Include routers
|
|
from .routers import health, dashboard, mappings, articles, validation, sync
|
|
app.include_router(health.router)
|
|
app.include_router(dashboard.router)
|
|
app.include_router(mappings.router)
|
|
app.include_router(articles.router)
|
|
app.include_router(validation.router)
|
|
app.include_router(sync.router)
|