Modern ERP Reports Application with microservices architecture Tech Stack: - Backend: FastAPI + python-oracledb (Oracle DB integration) - Frontend: Vue.js 3 + PrimeVue + Vite - Telegram Bot: python-telegram-bot + SQLite - Infrastructure: Shared database pool, JWT authentication, SSH tunnel Features: - FastAPI backend with async Oracle connection pool - Vue.js 3 responsive frontend with PrimeVue components - Telegram bot alternative interface - Microservices architecture with shared components - Complete deployment support (Linux Docker + Windows IIS) - Comprehensive testing (Playwright E2E + pytest) Repository Structure: - reports-app/ - Main application (backend, frontend, telegram-bot) - shared/ - Shared components (database pool, auth, utils) - deployment/ - Deployment scripts (Linux & Windows) - docs/ - Project documentation - security/ - Security scanning and git hooks
177 lines
7.0 KiB
Python
177 lines
7.0 KiB
Python
"""
|
|
API Router pentru managementul firmelor
|
|
"""
|
|
from fastapi import APIRouter, Depends, HTTPException, Request
|
|
from typing import List, Optional
|
|
import sys
|
|
import os
|
|
sys.path.append(os.path.join(os.path.dirname(__file__), '../../../../shared'))
|
|
|
|
from auth.dependencies import get_current_user
|
|
from auth.models import CurrentUser
|
|
from database.oracle_pool import oracle_pool
|
|
from pydantic import BaseModel
|
|
|
|
router = APIRouter(redirect_slashes=False)
|
|
|
|
class Company(BaseModel):
|
|
"""Model pentru firmă"""
|
|
id_firma: int # Cheia primară
|
|
name: str # Numele firmei
|
|
schema_name: str # Schema Oracle
|
|
fiscal_code: Optional[str] = None
|
|
is_active: bool = True
|
|
|
|
class CompanyListResponse(BaseModel):
|
|
"""Răspuns pentru lista de firme"""
|
|
companies: List[Company]
|
|
total_count: int
|
|
|
|
@router.get("", response_model=CompanyListResponse)
|
|
@router.get("/", response_model=CompanyListResponse)
|
|
async def get_user_companies(
|
|
request: Request,
|
|
current_user: CurrentUser = Depends(get_current_user)
|
|
):
|
|
"""
|
|
Obține lista firmelor la care utilizatorul are acces cu detalii complete
|
|
"""
|
|
print(f"[COMPANIES DEBUG] Request state: user={getattr(request.state, 'user', 'NOT_SET')}, is_authenticated={getattr(request.state, 'is_authenticated', 'NOT_SET')}")
|
|
print(f"[COMPANIES DEBUG] Authorization header: {request.headers.get('Authorization', 'NOT_SET')}")
|
|
try:
|
|
companies = []
|
|
|
|
# Obține toate companiile pentru utilizator direct din query-ul complet
|
|
# Ignorăm lista din JWT și recalculăm direct din Oracle pentru a obține toate cele 63 de companii
|
|
async with oracle_pool.get_connection() as connection:
|
|
with connection.cursor() as cursor:
|
|
try:
|
|
# Primul pas: obținem ID-ul utilizatorului din UTILIZATORI
|
|
cursor.execute("""
|
|
SELECT ID_UTIL, UTILIZATOR
|
|
FROM UTILIZATORI
|
|
WHERE UPPER(UTILIZATOR) = :username
|
|
""", {'username': current_user.username.upper()})
|
|
|
|
user_row = cursor.fetchone()
|
|
if not user_row:
|
|
print(f"User {current_user.username} not found in UTILIZATORI table")
|
|
return CompanyListResponse(companies=[], total_count=0)
|
|
|
|
user_id = user_row[0]
|
|
print(f"Found user {current_user.username} with ID: {user_id}")
|
|
|
|
# Al doilea pas: obținem TOATE companiile pentru programul 2
|
|
cursor.execute("""
|
|
SELECT A.ID_FIRMA, A.FIRMA, A.SCHEMA, A.COD_FISCAL
|
|
FROM V_NOM_FIRME A
|
|
WHERE A.ID_FIRMA IN (
|
|
SELECT ID_FIRMA
|
|
FROM VDEF_UTIL_FIRME
|
|
WHERE ID_PROGRAM = 2 AND ID_UTIL = :user_id
|
|
)
|
|
ORDER BY A.FIRMA
|
|
""", {'user_id': user_id})
|
|
|
|
companies_rows = cursor.fetchall()
|
|
|
|
for row in companies_rows:
|
|
id_firma = row[0]
|
|
firma_name = row[1]
|
|
schema = row[2]
|
|
fiscal_code = row[3] # Poate fi NULL
|
|
|
|
company = Company(
|
|
id_firma=id_firma,
|
|
name=firma_name,
|
|
schema_name=schema,
|
|
fiscal_code=fiscal_code,
|
|
is_active=True
|
|
)
|
|
companies.append(company)
|
|
|
|
print(f"Found {len(companies)} companies for user {current_user.username}")
|
|
|
|
except Exception as e:
|
|
print(f"Eroare la obținerea companiilor din Oracle: {e}")
|
|
# Fallback: folosim lista din JWT dacă query-ul Oracle eșuează
|
|
for company_id in current_user.companies:
|
|
try:
|
|
id_firma = int(company_id)
|
|
company = Company(
|
|
id_firma=id_firma,
|
|
name=f"Company {id_firma}",
|
|
schema_name="",
|
|
fiscal_code="",
|
|
is_active=True
|
|
)
|
|
companies.append(company)
|
|
except ValueError:
|
|
# Skip invalid company IDs
|
|
continue
|
|
|
|
return CompanyListResponse(
|
|
companies=companies,
|
|
total_count=len(companies)
|
|
)
|
|
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Eroare la obținerea listei de firme: {str(e)}")
|
|
|
|
@router.get("/{company_id}", response_model=Company)
|
|
async def get_company_details(
|
|
company_id: str,
|
|
current_user: CurrentUser = Depends(get_current_user)
|
|
):
|
|
"""
|
|
Obține detaliile unei firme specifice
|
|
"""
|
|
try:
|
|
# Verifică dacă utilizatorul are acces la firma specificată
|
|
if company_id not in current_user.companies:
|
|
raise HTTPException(status_code=403, detail=f"Nu aveți acces la firma {company_id}")
|
|
|
|
async with oracle_pool.get_connection() as connection:
|
|
with connection.cursor() as cursor:
|
|
# Query pentru detaliile firmei
|
|
company_query = """
|
|
SELECT ID_FIRMA, FIRMA, SCHEMA, COD_FISCAL
|
|
FROM V_NOM_FIRME
|
|
WHERE ID_FIRMA = :company_id
|
|
"""
|
|
|
|
cursor.execute(company_query, {'company_id': int(company_id)})
|
|
row = cursor.fetchone()
|
|
|
|
if not row:
|
|
raise HTTPException(status_code=404, detail=f"Firma {company_id} nu a fost găsită")
|
|
|
|
return Company(
|
|
id_firma=row[0],
|
|
name=row[1],
|
|
schema_name=row[2],
|
|
fiscal_code=row[3] or "",
|
|
is_active=True
|
|
)
|
|
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Eroare la obținerea detaliilor firmei: {str(e)}")
|
|
|
|
@router.get("/{company_id}/validate")
|
|
async def validate_company_access(
|
|
company_id: str,
|
|
current_user: CurrentUser = Depends(get_current_user)
|
|
):
|
|
"""
|
|
Validează dacă utilizatorul are acces la o firmă specificată
|
|
"""
|
|
has_access = company_id in current_user.companies
|
|
|
|
return {
|
|
"company_id": company_id,
|
|
"has_access": has_access,
|
|
"user": current_user.username,
|
|
"message": "Acces validat" if has_access else "Acces refuzat"
|
|
} |