feat: multi-Oracle server support with runtime switching
Complete implementation of multi-server Oracle database support: Backend: - Multi-pool Oracle with lazy loading per server - Email-to-server cache for automatic server discovery - JWT tokens include server_id claim - /auth/check-identity and /auth/check-email endpoints - /auth/my-servers endpoint for listing user's accessible servers - Server switch with password re-authentication Frontend: - New ServerSelector component for header dropdown - Multi-step login flow (identity → server → password) - Server switching from header with password modal - Mobile drawer menu with server selection - Dark mode support for all new components - URL bookmark support with ?server= query param Scripts: - Unified start.sh replacing start-prod.sh/start-test.sh - Unified ssh-tunnel.sh with multi-server support - Updated status.sh for new architecture Tests: - E2E tests for multi-server and single-server login flows - Backend unit tests for all new endpoints - Oracle multi-pool integration tests Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ Calendar service for fetching available accounting periods
|
||||
"""
|
||||
# import sys # Removed - no longer needed
|
||||
import os
|
||||
from typing import Optional
|
||||
|
||||
from shared.database.oracle_pool import oracle_pool
|
||||
from ..models.calendar import CalendarPeriod, CalendarPeriodsResponse
|
||||
@@ -22,10 +23,10 @@ class CalendarService:
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='schema', key_params=['company_id'])
|
||||
async def _get_schema(company_id: int) -> str:
|
||||
@cached(cache_type='schema', key_params=['company_id', 'server_id'])
|
||||
async def _get_schema(company_id: int, server_id: Optional[str] = None) -> str:
|
||||
"""Get schema for company (CACHED 24h)"""
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute("""
|
||||
SELECT schema FROM CONTAFIN_ORACLE.v_nom_firme
|
||||
@@ -35,19 +36,19 @@ class CalendarService:
|
||||
return result[0] if result else None
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='calendar_periods', key_params=['company_id'])
|
||||
async def get_available_periods(company_id: int) -> CalendarPeriodsResponse:
|
||||
@cached(cache_type='calendar_periods', key_params=['company_id', 'server_id'])
|
||||
async def get_available_periods(company_id: int, server_id: Optional[str] = None) -> CalendarPeriodsResponse:
|
||||
"""
|
||||
Get all available accounting periods for a company (CACHED 1h)
|
||||
|
||||
Returns periods ordered by year DESC, month DESC with Romanian month names.
|
||||
"""
|
||||
schema = await CalendarService._get_schema(company_id)
|
||||
schema = await CalendarService._get_schema(company_id, server_id)
|
||||
if not schema:
|
||||
logger.warning(f"Schema not found for company {company_id}")
|
||||
return CalendarPeriodsResponse(periods=[], current_period=None, total_count=0)
|
||||
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(f"""
|
||||
SELECT anul, luna
|
||||
|
||||
@@ -44,15 +44,15 @@ class DashboardService:
|
||||
return cte_sql, params
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='schema', key_params=['company_id'])
|
||||
async def _get_schema(company_id: int) -> str:
|
||||
@cached(cache_type='schema', key_params=['company_id', 'server_id'])
|
||||
async def _get_schema(company_id: int, server_id: Optional[str] = None) -> str:
|
||||
"""
|
||||
Obține schema pentru company_id (CACHED PERMANENT)
|
||||
|
||||
CRITICAL: Acest query este cel mai frecvent - executat la FIECARE request API.
|
||||
Cache permanent reduce queries cu 99.99%.
|
||||
"""
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
schema_query = """
|
||||
SELECT schema
|
||||
@@ -68,8 +68,8 @@ class DashboardService:
|
||||
return schema_result[0]
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='dashboard_summary', key_params=['company', 'username', 'luna', 'an'])
|
||||
async def get_complete_summary(company: str, username: str, luna: Optional[int] = None, an: Optional[int] = None, request: Optional[Request] = None) -> DashboardSummary:
|
||||
@cached(cache_type='dashboard_summary', key_params=['company', 'username', 'luna', 'an', 'server_id'])
|
||||
async def get_complete_summary(company: str, username: str, luna: Optional[int] = None, an: Optional[int] = None, request: Optional[Request] = None, server_id: Optional[str] = None) -> DashboardSummary:
|
||||
"""
|
||||
Obține toate datele pentru dashboard într-un singur apel (CACHED 30 min)
|
||||
Execută 2 query-uri separate: facturi și trezorerie
|
||||
@@ -80,14 +80,15 @@ class DashboardService:
|
||||
luna: Luna contabilă (1-12), opțional
|
||||
an: Anul contabil, opțional
|
||||
request: Request object pentru cache metadata
|
||||
server_id: ID-ul serverului Oracle (pentru multi-server)
|
||||
"""
|
||||
company_id = int(company)
|
||||
schema = await DashboardService._get_schema(company_id)
|
||||
schema = await DashboardService._get_schema(company_id, server_id)
|
||||
|
||||
# Construiește CTE pentru perioada curentă
|
||||
period_cte, period_params = DashboardService._build_period_cte(schema, luna, an)
|
||||
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
# Query 1: Statistici facturi cu breakdown pe perioade - FIXED ORA-00937
|
||||
@@ -565,8 +566,8 @@ class DashboardService:
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='dashboard_trends', key_params=['company_id', 'period', 'luna', 'an'])
|
||||
async def get_trends(company_id: int, period: str = "12m", luna: Optional[int] = None, an: Optional[int] = None, request: Optional[Request] = None) -> Dict[str, Any]:
|
||||
@cached(cache_type='dashboard_trends', key_params=['company_id', 'period', 'luna', 'an', 'server_id'])
|
||||
async def get_trends(company_id: int, period: str = "12m", luna: Optional[int] = None, an: Optional[int] = None, request: Optional[Request] = None, server_id: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""Get comprehensive trend analysis data for all dashboard indicators (CACHED 30 min)
|
||||
|
||||
Args:
|
||||
@@ -575,11 +576,12 @@ class DashboardService:
|
||||
luna: Luna contabilă (1-12), opțional - dacă nu e specificată, folosește MAX
|
||||
an: Anul contabil, opțional - dacă nu e specificat, folosește MAX
|
||||
request: Request object pentru cache metadata
|
||||
server_id: ID-ul serverului Oracle (pentru multi-server)
|
||||
"""
|
||||
try:
|
||||
schema = await DashboardService._get_schema(company_id)
|
||||
schema = await DashboardService._get_schema(company_id, server_id)
|
||||
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
# Determine current period from params or database
|
||||
@@ -962,7 +964,7 @@ class DashboardService:
|
||||
raise
|
||||
|
||||
@staticmethod
|
||||
async def get_detailed_data(company: str, data_type: str, luna: Optional[int] = None, an: Optional[int] = None, page: int = 1, page_size: int = 25, search: str = ""):
|
||||
async def get_detailed_data(company: str, data_type: str, luna: Optional[int] = None, an: Optional[int] = None, page: int = 1, page_size: int = 25, search: str = "", server_id: Optional[str] = None):
|
||||
"""
|
||||
Obține date detaliate pentru tabelele din dashboard
|
||||
Fixed to use existing vireg_parteneri view instead of missing tables
|
||||
@@ -975,9 +977,10 @@ class DashboardService:
|
||||
page: Pagina curentă
|
||||
page_size: Mărimea paginii
|
||||
search: Termen de căutare
|
||||
server_id: ID-ul serverului Oracle (pentru multi-server)
|
||||
"""
|
||||
logger.info(f"get_detailed_data called: company={company}, data_type={data_type}, luna={luna}, an={an}, page={page}")
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
try:
|
||||
# Get schema for company
|
||||
@@ -1168,14 +1171,15 @@ class DashboardService:
|
||||
return {"error": f"Database error: {str(e)}", "data": [], "total": 0}
|
||||
|
||||
@staticmethod
|
||||
async def get_performance_data(company_id: int, period: str = "7d") -> Dict[str, Any]:
|
||||
async def get_performance_data(company_id: int, period: str = "7d", server_id: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Calculează performanța încasări/plăți pentru perioada selectată
|
||||
|
||||
|
||||
Args:
|
||||
company_id: ID-ul companiei
|
||||
period: Perioada ("7d", "1m", "3m", "6m", "ytd", "12m")
|
||||
|
||||
server_id: ID-ul serverului Oracle (pentru multi-server)
|
||||
|
||||
Returns:
|
||||
{
|
||||
labels: List[str] - etichete pentru perioadele de timp
|
||||
@@ -1190,7 +1194,7 @@ class DashboardService:
|
||||
}
|
||||
"""
|
||||
try:
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
# Get schema
|
||||
schema_query = "SELECT schema FROM CONTAFIN_ORACLE.v_nom_firme WHERE id_firma = :company_id"
|
||||
@@ -1262,14 +1266,15 @@ class DashboardService:
|
||||
raise
|
||||
|
||||
@staticmethod
|
||||
async def get_cashflow_forecast(company_id: int, period: str = "7d") -> Dict[str, Any]:
|
||||
async def get_cashflow_forecast(company_id: int, period: str = "7d", server_id: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Calculează previziunea cash flow bazată pe scadențe
|
||||
|
||||
|
||||
Args:
|
||||
company_id: ID-ul companiei
|
||||
period: Perioada ("7d", "1m", "3m", "6m")
|
||||
|
||||
server_id: ID-ul serverului Oracle (pentru multi-server)
|
||||
|
||||
Returns:
|
||||
{
|
||||
periods: List[str] - perioadele de timp
|
||||
@@ -1282,7 +1287,7 @@ class DashboardService:
|
||||
}
|
||||
"""
|
||||
try:
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
# Get schema
|
||||
schema_query = "SELECT schema FROM CONTAFIN_ORACLE.v_nom_firme WHERE id_firma = :company_id"
|
||||
@@ -1347,8 +1352,8 @@ class DashboardService:
|
||||
raise
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='maturity_analysis', key_params=['company_id', 'period', 'luna', 'an'])
|
||||
async def get_maturity_analysis(company_id: int, period: str = "7d", luna: Optional[int] = None, an: Optional[int] = None, request: Optional[Request] = None) -> Dict[str, Any]:
|
||||
@cached(cache_type='maturity_analysis', key_params=['company_id', 'period', 'luna', 'an', 'server_id'])
|
||||
async def get_maturity_analysis(company_id: int, period: str = "7d", luna: Optional[int] = None, an: Optional[int] = None, request: Optional[Request] = None, server_id: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Analizează scadențele clienți vs furnizori cu date reale din Oracle (CACHED 30 min)
|
||||
|
||||
@@ -1357,6 +1362,7 @@ class DashboardService:
|
||||
period: Perioada ("7d", "1m", "3m", "6m", "12m", "over12m")
|
||||
luna: Luna contabilă (1-12), opțional
|
||||
an: Anul contabil, opțional
|
||||
server_id: ID-ul serverului Oracle (pentru multi-server)
|
||||
|
||||
Returns:
|
||||
{
|
||||
@@ -1367,7 +1373,7 @@ class DashboardService:
|
||||
}
|
||||
"""
|
||||
try:
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
# Get schema
|
||||
schema_query = "SELECT schema FROM CONTAFIN_ORACLE.v_nom_firme WHERE id_firma = :company_id"
|
||||
@@ -1546,8 +1552,8 @@ class DashboardService:
|
||||
raise
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='monthly_flows', key_params=['company', 'luna', 'an'])
|
||||
async def get_monthly_flows(company: int, luna: Optional[int] = None, an: Optional[int] = None, request: Optional[Request] = None) -> Dict[str, Any]:
|
||||
@cached(cache_type='monthly_flows', key_params=['company', 'luna', 'an', 'server_id'])
|
||||
async def get_monthly_flows(company: int, luna: Optional[int] = None, an: Optional[int] = None, request: Optional[Request] = None, server_id: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Obține fluxurile lunare de intrare și ieșire pentru luna curentă (CACHED 30 min)
|
||||
|
||||
@@ -1556,9 +1562,10 @@ class DashboardService:
|
||||
luna: Luna contabilă (1-12), opțional
|
||||
an: Anul contabil, opțional
|
||||
request: Request object pentru cache metadata
|
||||
server_id: ID-ul serverului Oracle (pentru multi-server)
|
||||
"""
|
||||
try:
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
# Obține schema
|
||||
company_id = company
|
||||
@@ -1640,8 +1647,8 @@ class DashboardService:
|
||||
raise
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='treasury_breakdown', key_params=['company', 'luna', 'an'])
|
||||
async def get_treasury_breakdown(company: int, luna: Optional[int] = None, an: Optional[int] = None, request: Optional[Request] = None) -> Dict[str, Any]:
|
||||
@cached(cache_type='treasury_breakdown', key_params=['company', 'luna', 'an', 'server_id'])
|
||||
async def get_treasury_breakdown(company: int, luna: Optional[int] = None, an: Optional[int] = None, request: Optional[Request] = None, server_id: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Obține breakdown-ul trezoreriei pe casă și bancă (CACHED 30 min)
|
||||
|
||||
@@ -1649,9 +1656,10 @@ class DashboardService:
|
||||
company: ID-ul firmei
|
||||
luna: Luna contabilă (1-12), opțional
|
||||
an: Anul contabil, opțional
|
||||
server_id: ID-ul serverului Oracle (pentru multi-server)
|
||||
"""
|
||||
try:
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
# Obține schema
|
||||
company_id = company
|
||||
@@ -1745,8 +1753,8 @@ class DashboardService:
|
||||
raise
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='net_balance_breakdown', key_params=['company', 'luna', 'an'])
|
||||
async def get_net_balance_breakdown(company: int, luna: Optional[int] = None, an: Optional[int] = None, request: Optional[Request] = None) -> Dict[str, Any]:
|
||||
@cached(cache_type='net_balance_breakdown', key_params=['company', 'luna', 'an', 'server_id'])
|
||||
async def get_net_balance_breakdown(company: int, luna: Optional[int] = None, an: Optional[int] = None, request: Optional[Request] = None, server_id: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Obține breakdown-ul balanței nete pe clienți și furnizori cu detaliere pe perioade (CACHED 30 min)
|
||||
|
||||
@@ -1754,9 +1762,10 @@ class DashboardService:
|
||||
company: ID-ul firmei
|
||||
luna: Luna contabilă (1-12), opțional
|
||||
an: Anul contabil, opțional
|
||||
server_id: ID-ul serverului Oracle (pentru multi-server)
|
||||
"""
|
||||
try:
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
# Obține schema
|
||||
company_id = company
|
||||
@@ -1938,12 +1947,13 @@ class DashboardService:
|
||||
raise
|
||||
|
||||
@staticmethod
|
||||
async def get_current_period(company: int) -> Dict[str, Any]:
|
||||
async def get_current_period(company: int, server_id: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Obține perioada curentă (an și lună) din calendarul Oracle
|
||||
|
||||
Args:
|
||||
company: ID-ul companiei
|
||||
server_id: ID-ul serverului Oracle (pentru multi-server)
|
||||
|
||||
Returns:
|
||||
{
|
||||
@@ -1953,7 +1963,7 @@ class DashboardService:
|
||||
}
|
||||
"""
|
||||
try:
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
# Obține schema
|
||||
company_id = company
|
||||
|
||||
@@ -278,14 +278,14 @@ class FinancialIndicatorsService:
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='schema', key_params=['company_id'])
|
||||
async def _get_schema(company_id: int) -> str:
|
||||
@cached(cache_type='schema', key_params=['company_id', 'server_id'])
|
||||
async def _get_schema(company_id: int, server_id: Optional[str] = None) -> str:
|
||||
"""
|
||||
Obține schema pentru company_id (CACHED PERMANENT)
|
||||
|
||||
Schema este stocată permanent în cache deoarece nu se schimbă.
|
||||
"""
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
schema_query = """
|
||||
SELECT schema
|
||||
@@ -319,11 +319,12 @@ class FinancialIndicatorsService:
|
||||
return f"SUM(CASE WHEN ({conditions}) THEN NVL({column}, 0) ELSE 0 END)"
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='fin_balance_sheet', key_params=['company_id', 'luna', 'an'])
|
||||
@cached(cache_type='fin_balance_sheet', key_params=['company_id', 'luna', 'an', 'server_id'])
|
||||
async def get_balance_sheet_aggregates(
|
||||
company_id: int,
|
||||
luna: int,
|
||||
an: int
|
||||
an: int,
|
||||
server_id: Optional[str] = None
|
||||
) -> BalanceSheetAggregates:
|
||||
"""
|
||||
Obține soldurile agregate din balanța de verificare pentru calculul
|
||||
@@ -343,9 +344,9 @@ class FinancialIndicatorsService:
|
||||
Raises:
|
||||
ValueError: Dacă schema nu este găsită pentru firma specificată
|
||||
"""
|
||||
schema = await FinancialIndicatorsService._get_schema(company_id)
|
||||
schema = await FinancialIndicatorsService._get_schema(company_id, server_id)
|
||||
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
# Construim query-ul cu CASE pentru fiecare categorie
|
||||
# Soldurile din VBAL: SOLDDEB (sold debitor), SOLDCRED (sold creditor)
|
||||
@@ -546,11 +547,12 @@ class FinancialIndicatorsService:
|
||||
return aggregates
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='fin_achizitii', key_params=['company_id', 'luna', 'an'])
|
||||
@cached(cache_type='fin_achizitii', key_params=['company_id', 'luna', 'an', 'server_id'])
|
||||
async def get_achizitii_ytd(
|
||||
company_id: int,
|
||||
luna: int,
|
||||
an: int
|
||||
an: int,
|
||||
server_id: Optional[str] = None
|
||||
) -> Decimal:
|
||||
"""
|
||||
Calculează totalul achizițiilor YTD din Registrul Jurnal (ACT).
|
||||
@@ -575,9 +577,9 @@ class FinancialIndicatorsService:
|
||||
Returns:
|
||||
Total achiziții YTD fără TVA (Decimal)
|
||||
"""
|
||||
schema = await FinancialIndicatorsService._get_schema(company_id)
|
||||
schema = await FinancialIndicatorsService._get_schema(company_id, server_id)
|
||||
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
query = f"""
|
||||
SELECT
|
||||
@@ -611,11 +613,12 @@ class FinancialIndicatorsService:
|
||||
return achizitii_total
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='fin_cashflow_vbal', key_params=['company_id', 'luna', 'an'])
|
||||
@cached(cache_type='fin_cashflow_vbal', key_params=['company_id', 'luna', 'an', 'server_id'])
|
||||
async def get_cashflow_from_vbal(
|
||||
company_id: int,
|
||||
luna: int,
|
||||
an: int
|
||||
an: int,
|
||||
server_id: Optional[str] = None
|
||||
) -> dict:
|
||||
"""
|
||||
Calculează datele de Cash Flow direct din VBAL (balanța de verificare).
|
||||
@@ -642,9 +645,9 @@ class FinancialIndicatorsService:
|
||||
- incasari_ytd: Încasări YTD (4111+461 TOTCRED)
|
||||
- plati_ytd: Plăți YTD (401+404+462 TOTDEB)
|
||||
"""
|
||||
schema = await FinancialIndicatorsService._get_schema(company_id)
|
||||
schema = await FinancialIndicatorsService._get_schema(company_id, server_id)
|
||||
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
query = f"""
|
||||
SELECT
|
||||
@@ -737,7 +740,8 @@ class FinancialIndicatorsService:
|
||||
async def calculate_liquidity_indicators(
|
||||
company_id: int,
|
||||
luna: int,
|
||||
an: int
|
||||
an: int,
|
||||
server_id: Optional[str] = None
|
||||
) -> LiquidityIndicators:
|
||||
"""
|
||||
Calculează indicatorii de lichiditate pentru evaluarea capacității
|
||||
@@ -763,7 +767,7 @@ class FinancialIndicatorsService:
|
||||
"""
|
||||
# Obținem agregatele din balanță
|
||||
aggregates = await FinancialIndicatorsService.get_balance_sheet_aggregates(
|
||||
company_id, luna, an
|
||||
company_id, luna, an, server_id
|
||||
)
|
||||
# Ensure aggregates is a BalanceSheetAggregates model (cache may return dict)
|
||||
if isinstance(aggregates, dict):
|
||||
@@ -906,11 +910,12 @@ class FinancialIndicatorsService:
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='fin_efficiency', key_params=['company_id', 'luna', 'an'])
|
||||
@cached(cache_type='fin_efficiency', key_params=['company_id', 'luna', 'an', 'server_id'])
|
||||
async def calculate_efficiency_indicators(
|
||||
company_id: int,
|
||||
luna: int,
|
||||
an: int
|
||||
an: int,
|
||||
server_id: Optional[str] = None
|
||||
) -> EfficiencyIndicators:
|
||||
"""
|
||||
Calculează indicatorii de eficiență pentru evaluarea vitezei de conversie
|
||||
@@ -944,7 +949,8 @@ class FinancialIndicatorsService:
|
||||
company=str(company_id),
|
||||
username="system", # System call for indicators
|
||||
luna=luna,
|
||||
an=an
|
||||
an=an,
|
||||
server_id=server_id
|
||||
)
|
||||
# Ensure summary is a DashboardSummary model (cache may return dict)
|
||||
if isinstance(summary, dict):
|
||||
@@ -953,7 +959,8 @@ class FinancialIndicatorsService:
|
||||
# Obținem datele din trends (facturări/încasări/achiziții/plăți lunare)
|
||||
trends = await DashboardService.get_trends(
|
||||
company_id=company_id,
|
||||
period='12m' # Ultimele 12 luni pentru media lunară
|
||||
period='12m', # Ultimele 12 luni pentru media lunară
|
||||
server_id=server_id
|
||||
)
|
||||
|
||||
# Extragem soldurile din summary
|
||||
@@ -1162,11 +1169,12 @@ class FinancialIndicatorsService:
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='fin_risk', key_params=['company_id', 'luna', 'an'])
|
||||
@cached(cache_type='fin_risk', key_params=['company_id', 'luna', 'an', 'server_id'])
|
||||
async def calculate_risk_indicators(
|
||||
company_id: int,
|
||||
luna: int,
|
||||
an: int
|
||||
an: int,
|
||||
server_id: Optional[str] = None
|
||||
) -> RiskIndicators:
|
||||
"""
|
||||
Calculează indicatorii de risc și aging pentru evaluarea sănătății
|
||||
@@ -1205,7 +1213,8 @@ class FinancialIndicatorsService:
|
||||
company=str(company_id),
|
||||
username="system", # System call for indicators
|
||||
luna=luna,
|
||||
an=an
|
||||
an=an,
|
||||
server_id=server_id
|
||||
)
|
||||
# Ensure summary is a DashboardSummary model (cache may return dict)
|
||||
if isinstance(summary, dict):
|
||||
@@ -1384,11 +1393,12 @@ class FinancialIndicatorsService:
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='fin_cashflow', key_params=['company_id', 'luna', 'an'])
|
||||
@cached(cache_type='fin_cashflow', key_params=['company_id', 'luna', 'an', 'server_id'])
|
||||
async def calculate_cashflow_indicators(
|
||||
company_id: int,
|
||||
luna: int,
|
||||
an: int
|
||||
an: int,
|
||||
server_id: Optional[str] = None
|
||||
) -> CashFlowIndicators:
|
||||
"""
|
||||
Calculează indicatorii de cash flow pentru evaluarea generării și
|
||||
@@ -1421,10 +1431,10 @@ class FinancialIndicatorsService:
|
||||
# Obținem datele de cash flow din VBAL (sursa preferată)
|
||||
# VBAL oferă date directe: RULCRED/RULDEB pentru lunar, TOTCRED/TOTDEB pentru YTD
|
||||
cf_data_curent = await FinancialIndicatorsService.get_cashflow_from_vbal(
|
||||
company_id, luna, an
|
||||
company_id, luna, an, server_id
|
||||
)
|
||||
cf_data_anterior = await FinancialIndicatorsService.get_cashflow_from_vbal(
|
||||
company_id, luna, an - 1
|
||||
company_id, luna, an - 1, server_id
|
||||
)
|
||||
|
||||
# Obținem datele din summary pentru datorii restante
|
||||
@@ -1432,7 +1442,8 @@ class FinancialIndicatorsService:
|
||||
company=str(company_id),
|
||||
username="system",
|
||||
luna=luna,
|
||||
an=an
|
||||
an=an,
|
||||
server_id=server_id
|
||||
)
|
||||
# Ensure summary is a DashboardSummary model (cache may return dict)
|
||||
if isinstance(summary, dict):
|
||||
@@ -1609,11 +1620,12 @@ class FinancialIndicatorsService:
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='fin_dynamics', key_params=['company_id', 'luna', 'an'])
|
||||
@cached(cache_type='fin_dynamics', key_params=['company_id', 'luna', 'an', 'server_id'])
|
||||
async def calculate_dynamics_indicators(
|
||||
company_id: int,
|
||||
luna: int,
|
||||
an: int
|
||||
an: int,
|
||||
server_id: Optional[str] = None
|
||||
) -> DynamicsIndicators:
|
||||
"""
|
||||
Calculează indicatorii de dinamică pentru evaluarea evoluției afacerii.
|
||||
@@ -1653,10 +1665,10 @@ class FinancialIndicatorsService:
|
||||
# Obținem agregatele pentru anul curent și anul anterior
|
||||
# Cifra de Afaceri (70x) din VBAL - FĂRĂ TVA
|
||||
aggregates_curent = await FinancialIndicatorsService.get_balance_sheet_aggregates(
|
||||
company_id, luna, an
|
||||
company_id, luna, an, server_id
|
||||
)
|
||||
aggregates_anterior = await FinancialIndicatorsService.get_balance_sheet_aggregates(
|
||||
company_id, luna, an - 1
|
||||
company_id, luna, an - 1, server_id
|
||||
)
|
||||
|
||||
# Ensure aggregates is a BalanceSheetAggregates model (cache may return dict)
|
||||
@@ -1674,10 +1686,10 @@ class FinancialIndicatorsService:
|
||||
# Include: 3x=4x (stocuri) + 6x=4x (servicii, consumabile)
|
||||
# Exclude: discount/rabat (40x=667/609)
|
||||
achizitii_curent = await FinancialIndicatorsService.get_achizitii_ytd(
|
||||
company_id, luna, an
|
||||
company_id, luna, an, server_id
|
||||
)
|
||||
achizitii_anterior = await FinancialIndicatorsService.get_achizitii_ytd(
|
||||
company_id, luna, an - 1
|
||||
company_id, luna, an - 1, server_id
|
||||
)
|
||||
total_achizitii_curent = float(achizitii_curent)
|
||||
total_achizitii_anterior = float(achizitii_anterior)
|
||||
@@ -1843,11 +1855,12 @@ class FinancialIndicatorsService:
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='fin_altman', key_params=['company_id', 'luna', 'an'])
|
||||
@cached(cache_type='fin_altman', key_params=['company_id', 'luna', 'an', 'server_id'])
|
||||
async def calculate_altman_zscore(
|
||||
company_id: int,
|
||||
luna: int,
|
||||
an: int
|
||||
an: int,
|
||||
server_id: Optional[str] = None
|
||||
) -> AltmanZScore:
|
||||
"""
|
||||
Calculează Altman Z-Score pentru evaluarea riscului de faliment.
|
||||
@@ -1880,7 +1893,7 @@ class FinancialIndicatorsService:
|
||||
"""
|
||||
# Obținem agregatele din balanță
|
||||
aggregates = await FinancialIndicatorsService.get_balance_sheet_aggregates(
|
||||
company_id, luna, an
|
||||
company_id, luna, an, server_id
|
||||
)
|
||||
# Ensure aggregates is a BalanceSheetAggregates model (cache may return dict)
|
||||
if isinstance(aggregates, dict):
|
||||
@@ -2088,11 +2101,12 @@ class FinancialIndicatorsService:
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='fin_profitability', key_params=['company_id', 'luna', 'an'])
|
||||
@cached(cache_type='fin_profitability', key_params=['company_id', 'luna', 'an', 'server_id'])
|
||||
async def calculate_profitability_indicators(
|
||||
company_id: int,
|
||||
luna: int,
|
||||
an: int
|
||||
an: int,
|
||||
server_id: Optional[str] = None
|
||||
) -> ProfitabilityIndicators:
|
||||
"""
|
||||
Calculează indicatorii de profitabilitate pentru evaluarea randamentului afacerii.
|
||||
@@ -2120,7 +2134,7 @@ class FinancialIndicatorsService:
|
||||
"""
|
||||
# Obținem agregatele din balanță (include venituri, cheltuieli, active, capital)
|
||||
aggregates = await FinancialIndicatorsService.get_balance_sheet_aggregates(
|
||||
company_id, luna, an
|
||||
company_id, luna, an, server_id
|
||||
)
|
||||
# Ensure aggregates is a BalanceSheetAggregates model (cache may return dict)
|
||||
if isinstance(aggregates, dict):
|
||||
@@ -2356,7 +2370,8 @@ class FinancialIndicatorsService:
|
||||
async def calculate_solvability_indicators(
|
||||
company_id: int,
|
||||
luna: int,
|
||||
an: int
|
||||
an: int,
|
||||
server_id: Optional[str] = None
|
||||
) -> SolvabilityIndicators:
|
||||
"""
|
||||
Calculează indicatorii de solvabilitate pentru evaluarea capacității
|
||||
@@ -2384,7 +2399,7 @@ class FinancialIndicatorsService:
|
||||
"""
|
||||
# Obținem agregatele din balanță
|
||||
aggregates = await FinancialIndicatorsService.get_balance_sheet_aggregates(
|
||||
company_id, luna, an
|
||||
company_id, luna, an, server_id
|
||||
)
|
||||
# Ensure aggregates is a BalanceSheetAggregates model (cache may return dict)
|
||||
if isinstance(aggregates, dict):
|
||||
@@ -2555,12 +2570,13 @@ class FinancialIndicatorsService:
|
||||
return periods
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='financial_indicators_historical', ttl=3600, key_params=['company_id', 'months', 'luna', 'an'])
|
||||
@cached(cache_type='financial_indicators_historical', ttl=3600, key_params=['company_id', 'months', 'luna', 'an', 'server_id'])
|
||||
async def get_historical_indicators(
|
||||
company_id: int,
|
||||
months: int = 12,
|
||||
luna: Optional[int] = None,
|
||||
an: Optional[int] = None
|
||||
an: Optional[int] = None,
|
||||
server_id: Optional[str] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Calculează indicatorii financiari pentru ultimele `months` luni
|
||||
@@ -2672,7 +2688,7 @@ class FinancialIndicatorsService:
|
||||
try:
|
||||
# Lichiditate
|
||||
lichiditate = await FinancialIndicatorsService.calculate_liquidity_indicators(
|
||||
company_id, period_luna, period_an
|
||||
company_id, period_luna, period_an, server_id
|
||||
)
|
||||
# Ensure lichiditate is a model (cache may return dict)
|
||||
if isinstance(lichiditate, dict):
|
||||
@@ -2690,7 +2706,7 @@ class FinancialIndicatorsService:
|
||||
|
||||
# Eficiență
|
||||
eficienta = await FinancialIndicatorsService.calculate_efficiency_indicators(
|
||||
company_id, period_luna, period_an
|
||||
company_id, period_luna, period_an, server_id
|
||||
)
|
||||
# Ensure eficienta is a model (cache may return dict)
|
||||
if isinstance(eficienta, dict):
|
||||
@@ -2706,7 +2722,7 @@ class FinancialIndicatorsService:
|
||||
|
||||
# Risc
|
||||
risc = await FinancialIndicatorsService.calculate_risk_indicators(
|
||||
company_id, period_luna, period_an
|
||||
company_id, period_luna, period_an, server_id
|
||||
)
|
||||
# Ensure risc is a model (cache may return dict)
|
||||
if isinstance(risc, dict):
|
||||
@@ -2725,7 +2741,7 @@ class FinancialIndicatorsService:
|
||||
|
||||
# Cash Flow
|
||||
cash_flow = await FinancialIndicatorsService.calculate_cashflow_indicators(
|
||||
company_id, period_luna, period_an
|
||||
company_id, period_luna, period_an, server_id
|
||||
)
|
||||
# Ensure cash_flow is a model (cache may return dict)
|
||||
if isinstance(cash_flow, dict):
|
||||
@@ -2742,7 +2758,7 @@ class FinancialIndicatorsService:
|
||||
|
||||
# Dinamica
|
||||
dinamica = await FinancialIndicatorsService.calculate_dynamics_indicators(
|
||||
company_id, period_luna, period_an
|
||||
company_id, period_luna, period_an, server_id
|
||||
)
|
||||
# Ensure dinamica is a model (cache may return dict)
|
||||
if isinstance(dinamica, dict):
|
||||
@@ -2758,7 +2774,7 @@ class FinancialIndicatorsService:
|
||||
|
||||
# Altman Z-Score
|
||||
altman = await FinancialIndicatorsService.calculate_altman_zscore(
|
||||
company_id, period_luna, period_an
|
||||
company_id, period_luna, period_an, server_id
|
||||
)
|
||||
# Ensure altman is a model (cache may return dict)
|
||||
if isinstance(altman, dict):
|
||||
@@ -2772,7 +2788,7 @@ class FinancialIndicatorsService:
|
||||
|
||||
# Profitabilitate
|
||||
profitabilitate = await FinancialIndicatorsService.calculate_profitability_indicators(
|
||||
company_id, period_luna, period_an
|
||||
company_id, period_luna, period_an, server_id
|
||||
)
|
||||
# Ensure profitabilitate is a model (cache may return dict)
|
||||
if isinstance(profitabilitate, dict):
|
||||
@@ -2795,7 +2811,7 @@ class FinancialIndicatorsService:
|
||||
|
||||
# Solvabilitate
|
||||
solvabilitate = await FinancialIndicatorsService.calculate_solvability_indicators(
|
||||
company_id, period_luna, period_an
|
||||
company_id, period_luna, period_an, server_id
|
||||
)
|
||||
# Ensure solvabilitate is a model (cache may return dict)
|
||||
if isinstance(solvabilitate, dict):
|
||||
@@ -2829,13 +2845,14 @@ class FinancialIndicatorsService:
|
||||
return historical_data
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='financial_indicators_sparklines', key_params=['company_id', 'luna', 'an', 'months'])
|
||||
@cached(cache_type='financial_indicators_sparklines', key_params=['company_id', 'luna', 'an', 'months', 'server_id'])
|
||||
async def get_indicators_with_sparklines(
|
||||
company_id: int,
|
||||
luna: int,
|
||||
an: int,
|
||||
months: int = 12,
|
||||
request: Optional[Request] = None
|
||||
request: Optional[Request] = None,
|
||||
server_id: Optional[str] = None
|
||||
) -> FinancialIndicatorsResponse:
|
||||
"""
|
||||
Calculează toți indicatorii financiari și adaugă datele de sparkline
|
||||
@@ -2858,32 +2875,32 @@ class FinancialIndicatorsService:
|
||||
|
||||
# Obținem datele istorice și indicatorii curenți în paralel
|
||||
historical_task = FinancialIndicatorsService.get_historical_indicators(
|
||||
company_id, months, luna, an
|
||||
company_id, months, luna, an, server_id
|
||||
)
|
||||
|
||||
lichiditate_task = FinancialIndicatorsService.calculate_liquidity_indicators(
|
||||
company_id, luna, an
|
||||
company_id, luna, an, server_id
|
||||
)
|
||||
eficienta_task = FinancialIndicatorsService.calculate_efficiency_indicators(
|
||||
company_id, luna, an
|
||||
company_id, luna, an, server_id
|
||||
)
|
||||
risc_task = FinancialIndicatorsService.calculate_risk_indicators(
|
||||
company_id, luna, an
|
||||
company_id, luna, an, server_id
|
||||
)
|
||||
cash_flow_task = FinancialIndicatorsService.calculate_cashflow_indicators(
|
||||
company_id, luna, an
|
||||
company_id, luna, an, server_id
|
||||
)
|
||||
dinamica_task = FinancialIndicatorsService.calculate_dynamics_indicators(
|
||||
company_id, luna, an
|
||||
company_id, luna, an, server_id
|
||||
)
|
||||
altman_task = FinancialIndicatorsService.calculate_altman_zscore(
|
||||
company_id, luna, an
|
||||
company_id, luna, an, server_id
|
||||
)
|
||||
profitabilitate_task = FinancialIndicatorsService.calculate_profitability_indicators(
|
||||
company_id, luna, an
|
||||
company_id, luna, an, server_id
|
||||
)
|
||||
solvabilitate_task = FinancialIndicatorsService.calculate_solvability_indicators(
|
||||
company_id, luna, an
|
||||
company_id, luna, an, server_id
|
||||
)
|
||||
|
||||
(
|
||||
|
||||
@@ -5,7 +5,7 @@ Service pentru logica facturi - Portează query-urile din aplicația Flask
|
||||
import os
|
||||
|
||||
from shared.database.oracle_pool import oracle_pool
|
||||
from typing import List, Tuple
|
||||
from typing import List, Tuple, Optional
|
||||
from ..models.invoice import Invoice, InvoiceFilter, InvoiceListResponse, InvoiceSummary
|
||||
from ..cache.decorators import cached
|
||||
from decimal import Decimal
|
||||
@@ -17,10 +17,10 @@ class InvoiceService:
|
||||
"""Service pentru gestionarea facturilor"""
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='schema', key_params=['company_id'])
|
||||
async def _get_schema(company_id: int) -> str:
|
||||
@cached(cache_type='schema', key_params=['company_id', 'server_id'])
|
||||
async def _get_schema(company_id: int, server_id: Optional[str] = None) -> str:
|
||||
"""Obține schema pentru company_id (CACHED PERMANENT)"""
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
schema_query = """
|
||||
SELECT schema
|
||||
@@ -36,15 +36,15 @@ class InvoiceService:
|
||||
return schema_result[0]
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='invoices', key_params=['filter_params', 'username'])
|
||||
async def get_invoices(filter_params: InvoiceFilter, username: str) -> InvoiceListResponse:
|
||||
@cached(cache_type='invoices', key_params=['filter_params', 'username', 'server_id'])
|
||||
async def get_invoices(filter_params: InvoiceFilter, username: str, server_id: Optional[str] = None) -> InvoiceListResponse:
|
||||
"""
|
||||
Obține lista de facturi - Query simplu pentru afișare în tabel (CACHED 10 min)
|
||||
"""
|
||||
company_id = int(filter_params.company)
|
||||
schema = await InvoiceService._get_schema(company_id)
|
||||
schema = await InvoiceService._get_schema(company_id, server_id)
|
||||
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
# Determină conturile în funcție de partner_type
|
||||
@@ -240,11 +240,11 @@ class InvoiceService:
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
async def get_invoice_details(company: str, invoice_number: str, username: str) -> Invoice:
|
||||
async def get_invoice_details(company: str, invoice_number: str, username: str, server_id: Optional[str] = None) -> Invoice:
|
||||
"""
|
||||
Obține detaliile unei facturi specifice
|
||||
"""
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
# Obține schema din v_nom_firme bazat pe id_firma
|
||||
company_id = int(company)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# import sys # Removed - no longer needed
|
||||
import os
|
||||
from typing import Optional, List, Tuple, Any
|
||||
|
||||
import oracledb
|
||||
from shared.database.oracle_pool import oracle_pool
|
||||
from ..models.treasury import BankCashRegister, RegisterFilter, RegisterListResponse, AccountingPeriod
|
||||
from ..cache.decorators import cached
|
||||
from decimal import Decimal
|
||||
from typing import Optional, List, Tuple, Any
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -15,10 +15,10 @@ class TreasuryService:
|
||||
"""Service pentru trezorerie - registru casă și bancă"""
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='schema', key_params=['company_id'])
|
||||
async def _get_schema(company_id: int) -> str:
|
||||
@cached(cache_type='schema', key_params=['company_id', 'server_id'])
|
||||
async def _get_schema(company_id: int, server_id: Optional[str] = None) -> str:
|
||||
"""Obține schema pentru company_id (CACHED PERMANENT)"""
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
schema_query = """
|
||||
SELECT schema
|
||||
@@ -99,8 +99,8 @@ class TreasuryService:
|
||||
return " UNION ALL ".join(queries)
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='treasury', key_params=['filter_params', 'username'])
|
||||
async def get_bank_cash_register(filter_params: RegisterFilter, username: str) -> RegisterListResponse:
|
||||
@cached(cache_type='treasury', key_params=['filter_params', 'username', 'server_id'])
|
||||
async def get_bank_cash_register(filter_params: RegisterFilter, username: str, server_id: Optional[str] = None) -> RegisterListResponse:
|
||||
"""
|
||||
Obține registrul de casă și bancă din vbancasa views (CACHED 10 min)
|
||||
|
||||
@@ -114,9 +114,9 @@ class TreasuryService:
|
||||
Toate în aceeași tranzacție!
|
||||
"""
|
||||
company_id = int(filter_params.company)
|
||||
schema = await TreasuryService._get_schema(company_id)
|
||||
schema = await TreasuryService._get_schema(company_id, server_id)
|
||||
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
|
||||
# Construiește query-ul pentru tipul de registru selectat
|
||||
@@ -350,14 +350,14 @@ class TreasuryService:
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='treasury', key_params=['company_id', 'register_type'])
|
||||
async def get_bank_cash_accounts(company_id: int, register_type: str) -> List[str]:
|
||||
@cached(cache_type='treasury', key_params=['company_id', 'register_type', 'server_id'])
|
||||
async def get_bank_cash_accounts(company_id: int, register_type: str, server_id: Optional[str] = None) -> List[str]:
|
||||
"""
|
||||
Obține lista distinctă de conturi bancă/casă (bancasa) pentru dropdown.
|
||||
Cached pentru performanță.
|
||||
IMPORTANT: Trebuie să setăm contextul PACK_SESIUNE înainte de a accesa vbancasa views!
|
||||
"""
|
||||
schema = await TreasuryService._get_schema(company_id)
|
||||
schema = await TreasuryService._get_schema(company_id, server_id)
|
||||
|
||||
# Map register_type to view
|
||||
view_map = {
|
||||
@@ -372,7 +372,7 @@ class TreasuryService:
|
||||
|
||||
view_name = view_map[register_type]
|
||||
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
# PL/SQL block to set session context and get accounts
|
||||
plsql_block = f"""
|
||||
|
||||
@@ -4,9 +4,9 @@ Refactored to use caching system for optimal performance
|
||||
"""
|
||||
# import sys # Removed - no longer needed
|
||||
import os
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
from shared.database.oracle_pool import oracle_pool
|
||||
from typing import Dict, Any
|
||||
from ..models.trial_balance import (
|
||||
TrialBalanceItem,
|
||||
TrialBalanceFilters,
|
||||
@@ -25,14 +25,14 @@ class TrialBalanceService:
|
||||
"""Service pentru gestionarea balanței de verificare cu cache"""
|
||||
|
||||
@staticmethod
|
||||
@cached(cache_type='schema', key_params=['company_id'])
|
||||
async def _get_schema(company_id: int) -> str:
|
||||
@cached(cache_type='schema', key_params=['company_id', 'server_id'])
|
||||
async def _get_schema(company_id: int, server_id: Optional[str] = None) -> str:
|
||||
"""
|
||||
Obține schema pentru company_id (CACHED 24h)
|
||||
|
||||
This is cached permanently because company schemas rarely change.
|
||||
"""
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
schema_query = """
|
||||
SELECT schema
|
||||
@@ -50,7 +50,7 @@ class TrialBalanceService:
|
||||
@staticmethod
|
||||
@cached(cache_type='trial_balance', key_params=['company_id', 'luna', 'an', 'cont_filter',
|
||||
'denumire_filter', 'sort_by', 'sort_order',
|
||||
'page', 'page_size', 'username'])
|
||||
'page', 'page_size', 'username', 'server_id'])
|
||||
async def get_trial_balance(
|
||||
company_id: int,
|
||||
luna: int,
|
||||
@@ -61,7 +61,8 @@ class TrialBalanceService:
|
||||
sort_order: str,
|
||||
page: int,
|
||||
page_size: int,
|
||||
username: str
|
||||
username: str,
|
||||
server_id: Optional[str] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Obține balanța de verificare sintetică (CACHED 10 min)
|
||||
@@ -80,12 +81,13 @@ class TrialBalanceService:
|
||||
page: Pagina
|
||||
page_size: Mărimea paginii
|
||||
username: Username pentru cache tracking
|
||||
server_id: Optional Oracle server identifier for multi-server support
|
||||
|
||||
Returns:
|
||||
Dictionary cu items, pagination, filters_applied
|
||||
"""
|
||||
# Get schema (cached separately)
|
||||
schema = await TrialBalanceService._get_schema(company_id)
|
||||
schema = await TrialBalanceService._get_schema(company_id, server_id)
|
||||
|
||||
# Validate sort_order
|
||||
if sort_order.lower() not in ['asc', 'desc']:
|
||||
@@ -97,7 +99,7 @@ class TrialBalanceService:
|
||||
if sort_by.upper() not in valid_sort_columns:
|
||||
sort_by = 'CONT'
|
||||
|
||||
async with oracle_pool.get_connection() as connection:
|
||||
async with oracle_pool.get_connection(server_id) as connection:
|
||||
with connection.cursor() as cursor:
|
||||
# Build base query for VBAL VIEW
|
||||
base_query = f"""
|
||||
|
||||
Reference in New Issue
Block a user